2013-02-14 3 views
2

Как я могу перебрать более groupby результатов в парах? То, что я пытался не совсем рабочий: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
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)] 

в итератор. То, что групповой итератор обернут вокруг базового итератора данных, аналогичен тому, как csv.reader обернут вокруг итератора основного файла. Вы получаете один проход через этот итератор и только один проход. Функция itertools.izip в процессе сопряжения элементов в groups приводит к тому, что итератор groups переходит от первого элемента ко второму. Поскольку вы получаете только один проход через итератор, первый элемент был израсходован, поэтому, когда вы вызываете list(g[1]), он пуст.

не так удовлетворяющие исправления этой проблемы заключается в преобразовании итераторов в groups в списки:

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

так itertools.izip не будет преждевременно потреблять их. Edit: С другой стороны, это исправление не так уж плохо. groups остается итератором и только превращает group в список, когда он потребляется.

+0

Ваша правка как поучительно, как обычно :) – root

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