2013-02-14 142 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