2010-08-09 5 views
7

Per illustrare, comincio con un elenco di 2-tuple:Come usare itertools.groupby quando il valore della chiave è negli elementi del iterabile?

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] 

rendimenti:

1 one 
2 two 
1 one 
3 three 
2 two 

Nel tentativo di indagare il motivo per cui:

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

Anche questo mi darà la stessa uscita:

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

voglio ottenere qualcosa di simile:

1 one, one 
2 two, two 
3 three 

Sto pensando questo è perché la chiave è all'interno della tupla all'interno della lista, quando in realtà la tupla viene spostato intorno come uno. C'è un modo per arrivare alla mia uscita desiderata? Forse groupby() non è adatto per questa attività?

risposta

9

groupby cluster consecutivi elementi del iterabile che hanno la stessa chiave. Per produrre l'output desiderato, è necessario innanzitutto ordinare 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

ho pensato 'grp' è un oggetto' itertool._grouper'. Quali altri tipi di azioni 'incorporate 'posso fare con' _grouper'? Vedo che l'hai trattato come un 'iterable' pure? Neat! – Kit

+0

@Kit: Credo che il principale fatto utile su 'grp' è che è un' iterable'. Finché non l'hai menzionato, non sapevo che fosse un oggetto "itertools._grouper'. Questo sembra essere un buon esempio della praticità della tipizzazione delle anatre. Non abbiamo bisogno di conoscere il tipo di 'grp', solo che implementa l'interfaccia' iterable'. – unutbu

+0

+1 per 'itemgetter' – Krastanov

2

Dal docs:

Il funzionamento groupby() è simile al filtro uniq in Unix. Lo standard genera un'interruzione o un nuovo gruppo ogni ora il valore della funzione chiave modifiche (motivo per cui è solitamente necessario per ordinare i dati utilizzando la stessa funzione chiave). Il comportamento di differisce da GROUP BY di SQL che aggrega gli elementi comuni indipendentemente dal loro ordine di input.

Dal momento che si sta ordinando le tuple lessicografico in ogni caso, si può chiamare sorted:

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

Rimuovere gli spazi attorno alle parentesi mi farebbe sentire caldo e confuso dentro;) –

+1

Sono un credente in \ t \ n \ n, il Signore degli spazi bianchi.Mi dice che il PEP-8 è sbagliato, e il mondo ha bisogno di più spazi bianchi! – katrielalex

6

Penso che un modo più pulito per ottenere il risultato desiderato è questo.

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

costruzione d è O (n), e ora sorted() è appena oltre la chiavi univoche anziché l'intero set di dati

Problemi correlati