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]]]