2

如何groupby成对迭代结果?我尝试的不太奏效:

from itertools import groupby,izip

groups = groupby([(1,2,3),(1,2),(1,2),(3,4,5),(3,4)],key=len)

def grouped(iterable, n):    
    return izip(*[iterable]*n)

for g, gg in grouped(groups,2):
    print list(g[1]), list(gg[1])

我得到的输出:

[] [(1, 2), (1, 2)]
[] [(3, 4)]

我想要的输出:

[(1, 2, 3)] [(1, 2), (1, 2)]
[(3, 4, 5)] [(3, 4)]
4

2 回答 2

2
import itertools as IT

groups = IT.groupby([(1,2,3),(1,2),(1,2),(3,4,5),(3,4)], key=len)
groups = (list(group) for key, group in groups)

def grouped(iterable, n):
    return IT.izip(*[iterable]*n)

for p1, p2  in grouped(groups, 2):
    print p1, p2

产量

[(1, 2, 3)] [(1, 2), (1, 2)]
[(3, 4, 5)] [(3, 4)]

您发布的代码非常有趣。它有一个世俗的问题,也有一个微妙的问题。

普通的问题是 itertools.groupby 返回一个迭代器,它在每次迭代时都输出一个键和一个组。由于您只对组感兴趣,而不是键,因此您需要类似

groups = (group for key, group in groups)

微妙的问题更难以解释——我不确定我是否完全理解它。这是我的猜测:返回的迭代器groupby已经改变了它的输入,

[(1,2,3),(1,2),(1,2),(3,4,5),(3,4)]

进入一个迭代器。groupby 迭代器环绕底层数据迭代器类似于 acsv.reader环绕底层文件对象迭代器。您通过此迭代器获得一次通过,并且仅通过一次。itertools.izip 函数在配对项目的过程中groups,使groups迭代器从第一个项目前进到第二个项目。由于您只通过迭代器,因此第一个项目已被消耗,因此当您调用list(g[1])它时它是空的。

解决这个问题的一个不太令人满意的方法是将迭代器转换groups为列表:

groups = (list(group) for key, group in groups)

所以itertools.izip不会过早地消耗它们。编辑:再想一想,这个修复还不错。groups仍然是一个迭代器,并且仅在使用时将其group转换为列表。

于 2013-02-14T13:35:06.317 回答
2

当您尝试查看 中的第二个键时groupby,您会强制它迭代到源迭代器的那么远。由于通常没有地方可以存储第一组中的项目,因此它们被简单地丢弃。

所以现在我们明白了为什么在我们尝试查看第二组的密钥(或项目)之前,我们需要确保我们已经存储了第一组的项目。

有些人肯定会讨厌这个,但是

>>> groups = groupby([(1, 2, 3), (1, 2), (1, 2), (3, 4, 5), (3, 4)], key=len)
>>> for i, j in ((list(i[1]), list(next(groups)[1])) for i in groups):
...     print i, j
... 
[(1, 2, 3)] [(1, 2), (1, 2)]
[(3, 4, 5)] [(3, 4)]
于 2013-02-14T13:44:11.700 回答