2010-08-09 14 views
7

Aby zilustrować, zacznę z listy 2-krotek:Jak używać itertools.groupby, gdy klucz jest w elementach iterable?

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] 

Wynik:

1 one 
2 two 
1 one 
3 three 
2 two 

W próbie zbadania dlaczego:

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')] 

Mimo to da mnie ta sama moc wyjściowa:

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

chcę uzyskać coś takiego:

1 one, one 
2 two, two 
3 three 

myślę to dlatego, że klucz jest w krotce wewnątrz listy, podczas gdy w rzeczywistości krotka dostaje przemieszczać jako jeden. Czy istnieje sposób, aby uzyskać pożądany wynik? Może groupby() nie nadaje się do tego zadania?

Odpowiedz

9

groupby klastry kolejne elementy iteracji, które mają ten sam klucz. Aby uzyskać pożądane wyniki, należy najpierw posortować 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

Myślałem 'grp' jest' itertool._grouper' przedmiot. Jakie inne rodzaje działań 'wbudowanych' mogę zrobić z' _grouper'? Widzę, że potraktowałeś to również jako "iterable"? Schludny! – Kit

+0

@Kit: Wierzę, że głównym pożytecznym faktem na temat 'grp' jest to, że jest to' iterable'. Dopóki tego nie wspomniałeś, nie wiedziałem, że to obiekt 'itertools._grouper'. Wydaje się to być dobrym przykładem wygody pisania na kaczkach. Nie musimy znać typu 'grp', tylko że implementuje interfejs' iterable'. – unutbu

+0

+1 dla 'itemgetter' – Krastanov

2

Z docs:

Działanie GroupBy() jest podobna do filtra uniq w Unix. To generuje przerwę lub nową grupę co godzinę zmienia się wartość funkcji klucza (dlatego zazwyczaj konieczne jest posortowanie danych przy użyciu tej samej funkcji klucza). To zachowanie różni się od grupy SQL GROUP BY , która agreguje wspólne elementy niezależnie od ich kolejności wprowadzania.

Ponieważ jesteś sortowania krotki leksykograficznie tak, można po prostu zadzwonić sorted:

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

Usunięcie spacji wokół nawiasów sprawiłoby, żebym się poczuła w środku ciepła;) –

+1

Jestem wierzący w \ t \ n \ n, Władca białych znaków.Mówi mi, że PEP-8 jest zły, a świat potrzebuje więcej białych znaków! – katrielalex

6

myślę czystszy sposób, aby uzyskać pożądany rezultat jest taki.

>>> 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'] 

budowy d wynosi O (n), a teraz sorted() jest tuż nad unikalnymi kluczami zamiast całego zestawu danych

Powiązane problemy