2013-03-22 5 views
5

Mi sento come se Python avesse un built-in per farlo. Prendi un elenco di elementi e trasformali in un dizionario che mappa le chiavi in ​​un elenco di elementi con quella chiave in comune.Raggruppamento di elementi con una chiave?

E 'abbastanza facile da fare:

# using defaultdict 
lookup = collections.defaultdict(list) 
for item in items: 
    lookup[key(item)].append(item) 

# or, using plain dict 
lookup = {} 
for item in items: 
    lookup.setdefault(key(item), []).append(item) 

Ma questo è abbastanza frequente di un caso d'uso che una funzione built-in sarebbe bello. Ho potuto implementare io stesso, come ad esempio:

def grouped(iterable, key): 
    result = {} 
    for item in iterable: 
     result.setdefault(key(item), []).append(item) 
    return result 

lookup = grouped(items, key) 

Questo è diverso itertools.groupby in alcuni modi importanti. Per ottenere lo stesso risultato da groupby, dovreste fare questo, che è un po 'brutto:

lookup = dict((k, list(v)) for k, v in groupby(sorted(items, key=key), key)) 

Alcuni esempi:

>>> items = range(10) 
>>> grouped(items, lambda x: x % 2) 
{0: [0, 2, 4, 6, 8], 1: [1, 3, 5, 7, 9]} 

>>> items = 'hello stack overflow how are you'.split() 
>>> grouped(items, len) 
{8: ['overflow'], 3: ['how', 'are', 'you'], 5: ['hello', 'stack']} 

C'è un modo migliore?

+1

Non vedo come si tratti di un "caso abbastanza frequente di utilizzo". Lo uso raramente e, quando devo, usare un 'defaultdict' è semplicemente perfetto. AFAIK non c'è alcun built-in che faccia ciò che vuoi da solo. – Bakuriu

+0

Probabilmente hai ragione, ma una parte di me pensa che sia altrettanto valido di un built-in come groupby. – FogleBird

risposta

3

Ho anche postato questa domanda su comp.lang.python, e il consenso sembra essere che questo non sia effettivamente abbastanza comune da giustificare una funzione integrata. Quindi, usare gli approcci più ovvi è il migliore. Funzionano e sono leggibili.

# using defaultdict 
lookup = collections.defaultdict(list) 
for item in items: 
    lookup[key(item)].append(item) 

# or, using plain dict 
lookup = {} 
for item in items: 
    lookup.setdefault(key(item), []).append(item) 

Stavo per cancellare la mia domanda, ma potrei anche lasciare questo qui nel caso qualcuno si imbatte in essa alla ricerca di informazioni.

+1

Vedere la mia risposta qui sotto per come si può estrarre una funzione per fare lo stesso come sopra, ma usando approssimativamente la stessa API di 'groupby'. – tobych

1

Se si voleva qualcosa con più o meno la stessa API come groupby, è possibile utilizzare:

def groupby2(iterable, keyfunc): 
    lookup = collections.defaultdict(list) 
    for item in iterable: 
     lookup[keyfunc(item)].append(item) 
    return lookup.iteritems() 

Ecco, questo è lo stesso come il tuo esempio di cui sopra, ma trasformato in una funzione che restituisce il iteritems della tabella di ricerca che si' ve costruito