2015-05-12 16 views
10

Ho un elenco semplice di oggetti univoci, alcuni dei quali possono condividere un determinato attributo con altri. Vorrei creare un elenco di liste annidato, con oggetti raggruppati per l'attributo dato. Come un esempio minimo, dato il seguente elenco:Annidare un elenco semplice basato su un criterio arbitrario

>>> flat = ["Shoes", "pants", "shirt", "tie", "jacket", "hat"] 

potrei voler gruppo che per lunghezza, per esempio:

>>> nest_by_length(flat) 
[['tie', 'hat'], ['shoes', 'pants', 'shirt'], ['jacket']] 

Ho visto un paio di similarquestions e suggestions. Tuttavia, in tutti questi casi, il nesting si basa sull'ordinamento della lista di input. Nel mio caso, l'ordinamento della lista di input è completamente imprevedibile, così come il numero di sotto-elenchi per l'output e il numero di articoli per sotto-elenco.

Esiste una funzione standard o un modo idiomatico per eseguire questa operazione?

risposta

10

un idioma comune per un elenco esistente è quello di utilizzare groupby in itertools:

from itertools import groupby 

flat = ["Shoes", "pants", "shirt", "tie", "jacket", "hat"] 

result=[] 
for k, g in groupby(sorted(flat, key=len), key=len): 
    result.append(list(g)) 

print result 

O, più conciso:

[list(g) for _,g in groupby(sorted(flat, key=len), key=len)] 

Stampe:

[['tie', 'hat'], ['Shoes', 'pants', 'shirt'], ['jacket']] 

input per groupby è raggruppati in gruppi in base al cambiamento del valore dell'output della funzione chiave, in questo caso len. In genere, è necessario preordinare l'elenco in base alla stessa funzione chiave, quindi viene chiamata per prima la funzione sorted.

Se l'elenco di origine non è ancora completa, o no sortable basa sui criteri (o si sarebbe solo preferisce un'altra opzione), creare un dict che mappa i criteri di un valore chiave univoca:

groups={} 
for e in flat: 
    groups.setdefault(len(e), []).append(e) 

print groups  
# {5: ['Shoes', 'pants', 'shirt'], 3: ['tie', 'hat'], 6: ['jacket']} 

È inoltre possibile utilizzare defaultdict piuttosto che setDefault con il valore della chiave arbitrario:

from collections import defaultdict 
groups=defaultdict(list) 
for e in flat: 
    groups[len(e)].append(e) 
# groups=defaultdict(<type 'list'>, {5: ['Shoes', 'pants', 'shirt'], 3: ['tie', 'hat'], 6: ['jacket']}) 

In entrambi i casi, quindi è possibile creare l'elenco nidificato da quella:

>>> [groups[k] for k in sorted(groups.keys())] 
[['tie', 'hat'], ['Shoes', 'pants', 'shirt'], ['jacket']] 
+0

Apprezzo la tua completezza. Sospettavo che ci fosse qualche funzione come groupby che non sapevo, ma il trucco del dizionario è semplicemente intelligente. Grazie! – Joe

Problemi correlati