2013-02-14 113 views
2

如何迭代groupby成对结果?我试过不是很工作:itertools.groupby:迭代遍历组pairwise

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
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如何包装底层文件对象迭代器。你只能通过这个迭代器一次,只有一次通过。 itertools.izip函数在配对groups中的项目过程中会导致迭代器从第一项前进到第二项。由于您只能通过迭代器一次,所以第一项已被使用,所以当您拨打list(g[1])时,它是空的。

一个 不那么满意 修复这个问题是迭代器转换成groups到列表:

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

所以itertools.izip不会过早食用。编辑:第二个想法,这个修复不是很糟糕。 groups仍然是一个迭代器,并且仅在消耗时才将group转换为列表。

+0

你的编辑和往常一样:) – root 2013-02-14 13:59:09

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)] 
+0

振聋发聩这是非常邪恶的:) – root 2013-02-14 13:46:48