0

我有一个清单

l=[(1,2),(1,6),(3,4),(3,6),(1,4),(4,3)]

我想返回一个列表,其中包含每个元组中第一个数字的列表。像这样的东西:

[[2,4,6],[4,6],[3]]

制作一个迭代列表的程序并编写一个完整的函数很容易。我想找到一个 oneliner - python 的方式来做这件事。有任何想法吗?

4

2 回答 2

10
>>> 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))]
于 2012-05-28T12:51:44.123 回答
2
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()

我知道它不是单行,但也许它比单行更容易阅读。

于 2012-05-28T13:23:46.890 回答