Python 按值分组列表
假设我有这样一个列表:Python 按值分组列表,python,list,grouping,Python,List,Grouping,假设我有这样一个列表: mylist = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]] 如何最优雅地将其分组以获得Python中的列表输出: [["A", "C"], ["B"], ["D", "E"]] 因此,这些值按secound值分组,但顺序保
mylist = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]]
如何最优雅地将其分组以获得Python中的列表输出:
[["A", "C"], ["B"], ["D", "E"]]
因此,这些值按secound值分组,但顺序保留
len = max(key for (item, key) in list)
newlist = [[] for i in range(len+1)]
for item,key in list:
newlist[key].append(item)
您可以在单个列表中完成此操作,可能更优雅,但O(n**2):
我不知道什么是优雅,但它确实可行:
oldlist = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]]
# change into: list = [["A", "C"], ["B"], ["D", "E"]]
order=[]
dic=dict()
for value,key in oldlist:
try:
dic[key].append(value)
except KeyError:
order.append(key)
dic[key]=[value]
newlist=map(dic.get, order)
print newlist
这将保留每个键第一次出现的顺序,以及每个键的项目顺序。它要求密钥是可散列的,但不指定其含义
values = set(map(lambda x:x[1], mylist))
newlist = [[y[0] for y in mylist if y[1]==x] for x in values]
编辑
另一个解决方案不需要导入,可读性更高,保留订单,比前一个解决方案短22%:
oldlist = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]]
newlist, dicpos = [],{}
for val,k in oldlist:
if k in dicpos:
newlist[dicpos[k]].extend(val)
else:
newlist.append([val])
dicpos[k] = len(dicpos)
print newlist
霍华德的回答简洁而优雅,但在最坏的情况下也是O(n^2)。对于具有大量分组键值的大型列表,您需要首先对列表进行排序,然后使用
itertools.groupby
:
>>> from itertools import groupby
>>> from operator import itemgetter
>>> seq = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]]
>>> seq.sort(key = itemgetter(1))
>>> groups = groupby(seq, itemgetter(1))
>>> [[item[0] for item in data] for (key, data) in groups]
[['A', 'C'], ['B'], ['D', 'E']]
编辑:
在看到eyequem的答案后,我改变了这一点:itemgetter(1)
比lambda x:x[1]
更好
>>> import collections
>>> D1 = collections.defaultdict(list)
>>> for element in L1:
... D1[element[1]].append(element[0])
...
>>> L2 = D1.values()
>>> print L2
[['A', 'C'], ['B'], ['D', 'E']]
>>>
基本上,如果列表已排序,则可以通过查看前面步骤构建的最后一个组来减少——您可以判断是否需要启动新组或修改现有组。
。。。或者l
bit是一个技巧,它使我们能够在Python中使用lambda
。(append
返回None
。返回比None
更有用的东西总是更好,但是,唉,Python就是这样。)set()
不一定要排序(尽管它是用于小整数值),如果您有一个长范围使用values=sorted(set(…
@sverre毕竟它不需要排序,除了set
没有顺序。恰好对于低整数,哈希函数是identity。我还不确定OP是否同时使用这两种顺序(组的顺序和组中的顺序);这和sverre的示例按键对组进行排序(his还假设为0..N连续范围)。lambda x:x[1]
可以替换为。感谢您。仅供那些遇到此问题的人参考,与其使用映射,不如使用理解:values=set(如果x[1],则列表中的x代表x)
+1用于使用itemgetter
。但请注意,由于您正在迭代由groupby
返回的迭代器,因此不需要list(g)
@Robert Rossney Eagle's eye.+1.顺便说一句,在你的代码中,我发现“数据”这个词太常见了,无法说明它是什么类型的数据,这很遗憾。但它需要导入。它真的比使用lambda好吗?我想知道。无论如何,为了可读性,我认为itemgetter也更好。另外,提醒t总是很好的操作符
模块的存在。我更喜欢lambda。我认为lambda更好。它总是好的,不需要提醒一个罕见的模块!我也更喜欢lambda,但我认为导入的数量不是一个重要的考虑因素,因为操作符模块是标准库的一部分。依赖关系不好,导入不重要t、 list
是Python中的一种数据类型,不建议将其用作变量名。我编辑了问题,因此它不会隐藏内置的list
关键字
>>> from itertools import groupby
>>> from operator import itemgetter
>>> seq = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]]
>>> seq.sort(key = itemgetter(1))
>>> groups = groupby(seq, itemgetter(1))
>>> [[item[0] for item in data] for (key, data) in groups]
[['A', 'C'], ['B'], ['D', 'E']]
>>> import collections
>>> D1 = collections.defaultdict(list)
>>> for element in L1:
... D1[element[1]].append(element[0])
...
>>> L2 = D1.values()
>>> print L2
[['A', 'C'], ['B'], ['D', 'E']]
>>>
>>> xs = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]]
>>> xs.sort(key=lambda x: x[1])
>>> reduce(lambda l, x: (l.append([x]) if l[-1][0][1] != x[1] else l[-1].append(x)) or l, xs[1:], [[xs[0]]]) if xs else []
[[['A', 0], ['C', 0]], [['B', 1]], [['D', 2], ['E', 2]]]