2010-08-09 4 views
7

Для иллюстрации, я начинаю со списком 2-кортежей:Как использовать itertools.groupby, когда значение ключа находится в элементах итерабельного?

import itertools 
import operator 

raw = [(1, "one"), 
     (2, "two"), 
     (1, "one"), 
     (3, "three"), 
     (2, "two")] 

for key, grp in itertools.groupby(raw, key=lambda item: item[0]): 
    print key, list(grp).pop()[1] 

урожайности:

1 one 
2 two 
1 one 
3 three 
2 two 

В попытке выяснить, почему:

for key, grp in itertools.groupby(raw, key=lambda item: item[0]): 
    print key, list(grp) 

# ---- OUTPUT ---- 
1 [(1, 'one')] 
2 [(2, 'two')] 
1 [(1, 'one')] 
3 [(3, 'three')] 
2 [(2, 'two')] 

Даже это даст мне тот же выход:

for key, grp in itertools.groupby(raw, key=operator.itemgetter(0)): 
    print key, list(grp) 

Я хочу, чтобы получить что-то вроде:

1 one, one 
2 two, two 
3 three 

Я думаю это потому, что ключ находится в кортеже внутри списка, когда на самом деле кортеж получает перемещаются как единое целое. Есть ли способ достичь желаемого результата? Может быть groupby() не подходит для этой задачи?

ответ

9

groupby кластер последовательный элементы итерации, имеющие один и тот же ключ. Для получения желаемого результата вы должны сначала отсортировать raw.

for key, grp in itertools.groupby(sorted(raw), key=operator.itemgetter(0)): 
    print key, map(operator.itemgetter(1), grp) 

# 1 ['one', 'one'] 
# 2 ['two', 'two'] 
# 3 ['three'] 
+0

Я думал, что 'grp' является' itertool._grouper' объект. Какие еще «встроенные» действия можно сделать с помощью «_grouper»? Я вижу, что вы рассматривали его как «итерируемый»? Ухоженная! – Kit

+0

@Kit: Я считаю, что основным полезным фактом о 'grp' является то, что он является« итерируемым ». Пока вы не упомянули об этом, я не знал, что это объект 'itertools._grouper'. Это, по-видимому, хороший пример удобства утиной печати. Нам не нужно знать тип 'grp', только он реализует интерфейс' iterable'. – unutbu

+0

+1 для 'itemgetter' – Krastanov

2

Из docs:

Работа GroupBy() подобна к фильтру UniQ в Unix. Он генерирует разрыв или новую группу каждые время, когда значение ключевой функции изменяется (поэтому обычно необходимо отсортировать данные , используя ту же ключевую функцию). Это поведение отличается от SQL GROUP BY , который объединяет общие элементы независимо от их порядка ввода.

Поскольку вы сортировка кортежей лексический в любом случае, вы можете просто позвонить sorted:

for key, grp in itertools.groupby(sorted(raw), key = operator.itemgetter(0)): 
    print(key, list(map(operator.itemgetter(1), list(grp)))) 
+6

Удаление пробелов вокруг круглых скобок заставил бы меня чувствовать себя теплым и нечетким внутри;) –

+1

Я верующий в \ t \ n \ n, Властелине Пространства.Он говорит мне, что PEP-8 ошибается, и миру нужно больше пробелов! – katrielalex

6

Я думаю, что уборщик способ получить желаемый результат заключается в следующем.

>>> from collections import defaultdict 
>>> d=defaultdict(list) 
>>> for k,v in raw: 
... d[k].append(v) 
... 
>>> for k,v in sorted(d.items()): 
... print k, v 
... 
1 ['one', 'one'] 
2 ['two', 'two'] 
3 ['three'] 

здание d О (п), а теперь sorted() чуть больше уникальных ключей вместо всего набора данных