Comprensione del dizionario Python


386

È possibile creare una comprensione del dizionario in Python (per le chiavi)?

Senza la comprensione dell'elenco, puoi usare qualcosa del genere:

l = []
for n in range(1, 11):
    l.append(n)

Siamo in grado di ridurre questo ad una lista di comprensione: l = [n for n in range(1, 11)].

Tuttavia, supponiamo che io voglia impostare le chiavi di un dizionario sullo stesso valore. Posso fare:

d = {}
for n in range(1, 11):
     d[n] = True # same value for each

Ho provato questo:

d = {}
d[i for i in range(1, 11)] = True

Tuttavia, ottengo un SyntaxErrorsu for.

Inoltre (non ho bisogno di questa parte, ma mi chiedo solo), puoi impostare le chiavi di un dizionario su un insieme di valori diversi, come questo:

d = {}
for n in range(1, 11):
    d[n] = n

Questo è possibile con una comprensione del dizionario?

d = {}
d[i for i in range(1, 11)] = [x for x in range(1, 11)]

Ciò solleva anche una SyntaxErrorsul for.


3
Per informazioni sui futuri lettori: le matrici NumPy ti consentono di impostare più elementi su un singolo valore o elenco di valori, come stai cercando di fare. Sebbene se non hai già un motivo per usare NumPy, probabilmente non ne vale la pena solo per questa funzione.
David Z,

Risposte:


520

In Python 2.7+ ci sono delle comprensioni del dizionario , ma non funzionano esattamente come stai provando. Come una comprensione dell'elenco, creano un nuovo dizionario; non puoi usarli per aggiungere chiavi a un dizionario esistente. Inoltre, devi specificare le chiavi e i valori, anche se ovviamente puoi specificare un valore fittizio, se lo desideri.

>>> d = {n: n**2 for n in range(5)}
>>> print d
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

Se vuoi impostarli tutti su True:

>>> d = {n: True for n in range(5)}
>>> print d
{0: True, 1: True, 2: True, 3: True, 4: True}

Quello che sembra chiedere è un modo per impostare più chiavi contemporaneamente su un dizionario esistente. Non esiste un collegamento diretto per questo. Puoi eseguire il loop come hai già mostrato oppure utilizzare una comprensione del dizionario per creare un nuovo dict con i nuovi valori, quindi eseguire oldDict.update(newDict)l'unione dei nuovi valori nel vecchio dict.


15
FWIW, dict.updatepuò anche accettare un iterabile di coppie chiave-valore proprio come il dictcostruttore
mgilson

6
Si noti che se si desidera creare un dizionario con tutti i valori uguali, utilizzare dict.fromkeys(). Quindi, per impostare tutti i valori su True, usare dict.fromkeys(range(5), True). Attenzione, il valore non viene copiato , quindi potresti voler evitare questo quando hai un valore mutabile; sarà condiviso tra tutte le chiavi.
Martijn Pieters

2
Nota: le chiavi possono essere il risultato di un metodo così: { n*2 : n for n in range(3) } => {0: 0, 2: 1, 4: 2}. Entrambi può essere fatto nella stessa espressione: { n*2 : n*3 for n in range(3) } => { 0: 0, 2: 3, 4: 6 }.
Zaaier,

151

Puoi usare il dict.fromkeysmetodo class ...

>>> dict.fromkeys(range(5), True)
{0: True, 1: True, 2: True, 3: True, 4: True}

Questo è il modo più veloce per creare un dizionario in cui tutte le chiavi corrispondono allo stesso valore.

Ma non non usare questo con oggetti mutabili :

d = dict.fromkeys(range(5), [])
# {0: [], 1: [], 2: [], 3: [], 4: []}
d[1].append(2)
# {0: [2], 1: [2], 2: [2], 3: [2], 4: [2]} !!!

Se in realtà non è necessario inizializzare tutte le chiavi, defaultdictpotrebbe essere utile anche una:

from collections import defaultdict
d = defaultdict(True)

Per rispondere alla seconda parte, una comprensione del dettato è proprio ciò di cui hai bisogno:

{k: k for k in range(10)}

Probabilmente non dovresti farlo, ma potresti anche creare una sottoclasse dictche funziona in qualche modo come defaultdictse esegui l'override __missing__:

>>> class KeyDict(dict):
...    def __missing__(self, key):
...       #self[key] = key  # Maybe add this also?
...       return key
... 
>>> d = KeyDict()
>>> d[1]
1
>>> d[2]
2
>>> d[3]
3
>>> print(d)
{}

Si noti che nel caso di d = defaultdict(lambda: True), la lambda non è richiesta in quanto True è (o non dovrebbe) essere mutabile.
rhbvkleef,

28
>>> {i:i for i in range(1, 11)}
{1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10}

22

Mi piace molto il commento di @mgilson, poiché se hai due iterabili, uno che corrisponde alle chiavi e l'altro ai valori, puoi anche fare quanto segue.

keys = ['a', 'b', 'c']
values = [1, 2, 3]
d = dict(zip(keys, values))

dando

d = {'a': 1, 'b': 2, 'c': 3}


4
Utilizzando Dict Comprensione:{i:j for i in keys for j in values}
LoMaPh

11

Usa dict () in un elenco di tuple, questa soluzione ti permetterà di avere valori arbitrari in ogni elenco, purché abbiano la stessa lunghezza

i_s = range(1, 11)
x_s = range(1, 11)
# x_s = range(11, 1, -1) # Also works
d = dict([(i_s[index], x_s[index], ) for index in range(len(i_s))])

12
Come nota a d = dict(zip(i_s,x_s))
margine

10

Considera questo esempio di conteggio della ricorrenza delle parole in un elenco usando la comprensione del dizionario

my_list = ['hello', 'hi', 'hello', 'today', 'morning', 'again', 'hello']
my_dict = {k:my_list.count(k) for k in my_list}
print(my_dict)

E il risultato è

{'again': 1, 'hi': 1, 'hello': 3, 'today': 1, 'morning': 1}

Questo è interessante, anche se non il più efficiente, poiché
conterai

7

Lo scopo principale della comprensione di un elenco è quello di creare un nuovo elenco basato su un altro senza modificare o distruggere l'elenco originale.

Invece di scrivere

    l = []
    for n in range(1, 11):
        l.append(n)

o

    l = [n for n in range(1, 11)]

dovresti solo scrivere

    l = range(1, 11)

Nei due blocchi di codice in alto stai creando un nuovo elenco, scorrendo attraverso di esso e restituendo ogni elemento. È solo un modo costoso per creare una copia dell'elenco.

Per ottenere un nuovo dizionario con tutte le chiavi impostate sullo stesso valore basato su un altro dict, procedere come segue:

    old_dict = {'a': 1, 'c': 3, 'b': 2}
    new_dict = { key:'your value here' for key in old_dict.keys()}

Stai ricevendo un SyntaxError perché quando scrivi

    d = {}
    d[i for i in range(1, 11)] = True

stai sostanzialmente dicendo: "Imposta la mia chiave 'i per i nell'intervallo (1, 11)' su Vero" e "i per i nell'intervallo (1, 11)" non è una chiave valida, è solo un errore di sintassi. Se dicts supportasse gli elenchi come chiavi, faresti qualcosa del genere

    d[[i for i in range(1, 11)]] = True

e non

    d[i for i in range(1, 11)] = True

ma gli elenchi non sono cancellabili, quindi non puoi usarli come chiavi dict.


-3

non puoi hash un elenco come quello. prova questo invece, usa le tuple

d[tuple([i for i in range(1,11)])] = True
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.