itertools.groupby:成对迭代组

时间:2013-02-14 13:15:47

标签: python itertools

如何成对迭代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)]

2 个答案:

答案 0 :(得分: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迭代器包含在底层数据迭代器中,类似于csv.reader围绕底层文件对象迭代器的方式。你通过这个迭代器得到一次通过,只有一次通过。在groups中配对项目的过程中,itertools.izip函数会导致groups迭代器从第一个项目前进到第二个项目。由于您只通过迭代器一次,所以第一项已被消耗,因此当您调用list(g[1])时它是空的。

不那么令人满意修复此问题的方法是将groups中的迭代器转换为列表:

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

所以itertools.izip不会过早消耗它们。编辑:第二个想法,这个修复并不是那么糟糕。 groups仍然是一个迭代器,只有在group消耗时才将{{1}}转换为列表。

答案 1 :(得分: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)]