2009-06-06 28 views
167

Voglio creare un dizionario i cui valori siano elenchi. Per esempio:Python che crea un dizionario di liste

{ 
    1: ['1'], 
    2: ['1','2'], 
    3: ['2'] 
} 

Se lo faccio:

d = dict() 
a = ['1', '2'] 
for i in a: 
    for j in range(int(i), int(i) + 2): 
     d[j].append(i) 

ottengo un KeyError, a causa d [...] non è una lista. In questo caso, posso aggiungere il seguente codice dopo l'assegnazione di a per inizializzare il dizionario.

for x in range(1, 4): 
    d[x] = list() 

C'è un modo migliore per farlo? Diciamo che non conosco le chiavi di cui ho bisogno fino a quando non sono nel secondo ciclo for. Per esempio:

class relation: 
    scope_list = list() 
... 
d = dict() 
for relation in relation_list: 
    for scope_item in relation.scope_list: 
     d[scope_item].append(relation) 

Un'alternativa sarebbe poi sostituendo

d[scope_item].append(relation) 

con

if d.has_key(scope_item): 
    d[scope_item].append(relation) 
else: 
    d[scope_item] = [relation,] 

Qual è il modo migliore per gestire questa situazione? Idealmente, l'aggiunta "funzionerebbe". C'è un modo per esprimere che voglio un dizionario di liste vuote, anche se non conosco tutte le chiavi quando creo la lista per la prima volta?

risposta

211

È possibile utilizzare defaultdict:

>>> from collections import defaultdict 
>>> d = defaultdict(list) 
>>> for i in a: 
... for j in range(int(i), int(i) + 2): 
...  d[j].append(i) 
... 
>>> d 
defaultdict(<type 'list'>, {1: ['1'], 2: ['1', '2'], 3: ['2']}) 
>>> d.items() 
[(1, ['1']), (2, ['1', '2']), (3, ['2'])] 
+0

Anche altri dizionari nel modulo 'collections' funzionano in questo modo, ad esempio' collections.OrderedDict'. – txsaw1

+1

Oh. È grandioso E non devi inizializzare su '= []'. Roba buona! –

21

Uso setdefault:

d = dict() 
a = ['1', '2'] 
for i in a: 
    for j in range(int(i), int(i) + 2): 
     d.setdefault(j, []).append(i) 

print d # prints {1: ['1'], 2: ['1', '2'], 3: ['2']} 

La funzione piuttosto stranamente nome setdefault dice "Prendi il valore con questa chiave, o se quella chiave non c'è, aggiungere questo valore e poi restituirlo."

Modifica: Come altri hanno giustamente sottolineato, defaultdict è una scelta migliore e più moderna. setdefault è ancora utile nelle versioni precedenti di Python (precedenti alla 2.5).

+2

Questo funziona, ma di solito è preferibile utilizzare defaultdict quando è disponibile. –

+0

@David, sì, setdefault non è stato il pezzo più brillante del design, mi dispiace, non è quasi mai la scelta migliore. Penso che noi (i committenti di Python) abbiamo riscattato la nostra reputazione collettiva con collections.defaultdict, però ;-). –

+0

@DavidZ, setdefault è diverso da defaultdict, in quanto è più flessibile: altrimenti, come si specificano valori predefiniti diversi per chiavi di dizionario diverse? –

37

Si può costruire con comprensione lista come questa:

>>> dict((i, range(int(i), int(i) + 2)) for i in ['1', '2']) 
{'1': [1, 2], '2': [2, 3]} 

E per la seconda parte della tua domanda utilizzare defaultdict

>>> from collections import defaultdict 
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)] 
>>> d = defaultdict(list) 
>>> for k, v in s: 
     d[k].append(v) 

>>> d.items() 
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])] 
1

La tua domanda ha già avuto risposta, ma IIRC puoi sostituire li nes come:

if d.has_key(scope_item): 

con:

if scope_item in d: 

Cioè, d riferimenti d.keys() in quella costruzione. A volte lo defaultdict non è l'opzione migliore (ad esempio, se si desidera eseguire più righe di codice dopo lo else associato allo), e trovo che la sintassi in sia più facile da leggere.

Problemi correlati