我有一个清单
l=[(1,2),(1,6),(3,4),(3,6),(1,4),(4,3)]
我想返回一个列表,其中包含每个元组中第一个数字的列表。像这样的东西:
[[2,4,6],[4,6],[3]]
制作一个迭代列表的程序并编写一个完整的函数很容易。我想找到一个 oneliner - python 的方式来做这件事。有任何想法吗?
>>> from itertools import groupby
>>> from operator import itemgetter
>>> L = [(1,2), (1,6), (3,4), (3,6), (1,4), (4,3)]
>>> [[y for x, y in v] for k, v in groupby(sorted(L), itemgetter(0))]
[[2, 4, 6], [4, 6], [3]]
解释
这通过使用itertools.groupby
. groupby
在可迭代对象中查找连续组,通过键、组对返回迭代器。
给定的参数groupby
是一个键函数,itemgetter(0)
它为每个元组调用,返回第一项作为键groupby
。
groupby
按原始顺序对元素进行分组,因此如果要按列表中的第一个数字进行分组,则必须首先对其进行排序,以便groupby
可以按升序遍历第一个数字并实际对它们进行分组。
>>> sorted(L)
[(1, 2), (1, 4), (1, 6), (3, 4), (3, 6), (4, 3)]
有一个排序列表,您可以在其中清楚地看到如果您回顾最终输出将创建的组。现在您可以使用groupby
显示键、组对。
[(1, <itertools._grouper object at 0x02BB7ED0>), (3, <itertools._grouper object at 0x02BB7CF0>), (4, <itertools._grouper object at 0x02BB7E30>)]
这是按第一个数字分组的排序项目。groupby
将每个键的组作为迭代器返回,这很好而且非常有效,但是对于这个例子,我们将把它转换为 alist
以确保它正常工作。
>>> [(k, list(v)) for k,v in groupby(sorted(L), itemgetter(0))]
[(1, [(1, 2), (1, 4), (1, 6)]), (3, [(3, 4), (3, 6)]), (4, [(4, 3)])]
这几乎是正确的,但所需的输出仅显示每个列表中组中的第二个数字。因此,以下实现了预期的结果。
[[y for x, y in v] for k, v in groupby(sorted(L), itemgetter(0))]
l = [(1, 2), (1, 6), (3, 4), (3, 6), (1, 4), (4, 3)]
d = {}
for (k, v) in l:
d.setdefault(k, []).append(v)
print d.values()
我知道它不是单行,但也许它比单行更容易阅读。