Risposte:
Hai già capito: A if test else B
è un'espressione valida di Python. L'unico problema con la comprensione del dict come mostrato è che il posto per un'espressione in una comprensione del dict deve avere due espressioni, separate da due punti:
{ (some_key if condition else default_key):(something_if_true if condition
else something_if_false) for key, value in dict_.items() }
La if
clausola finale funge da filtro, che è diverso dall'espressione condizionale.
{(a if condition else b): value for key, value in dict.items()}
funzionerà.
@ Risposta di Marcin copre tutto, ma nel caso qualcuno volesse vedere un esempio reale, ne aggiungo due di seguito:
Supponiamo che tu abbia il seguente dizionario di set
d = {'key1': {'a', 'b', 'c'}, 'key2': {'foo', 'bar'}, 'key3': {'so', 'sad'}}
e vuoi creare un nuovo dizionario le cui chiavi indicano se la stringa 'a'
è contenuta nei valori oppure no, puoi usarla
dout = {"a_in_values_of_{}".format(k) if 'a' in v else "a_not_in_values_of_{}".format(k): v for k, v in d.items()}
quale cede
{'a_in_values_of_key1': {'a', 'b', 'c'},
'a_not_in_values_of_key2': {'bar', 'foo'},
'a_not_in_values_of_key3': {'sad', 'so'}}
Supponiamo che tu abbia due dizionari come questo
d1 = {'bad_key1': {'a', 'b', 'c'}, 'bad_key2': {'foo', 'bar'}, 'bad_key3': {'so', 'sad'}}
d2 = {'good_key1': {'foo', 'bar', 'xyz'}, 'good_key2': {'a', 'b', 'c'}}
e vuoi sostituire le chiavi d1
con quelle di d2
se i rispettivi valori sono identici, potresti farlo
# here we assume that the values in d2 are unique
# Python 2
dout2 = {d2.keys()[d2.values().index(v1)] if v1 in d2.values() else k1: v1 for k1, v1 in d1.items()}
# Python 3
dout2 = {list(d2.keys())[list(d2.values()).index(v1)] if v1 in d2.values() else k1: v1 for k1, v1 in d1.items()}
che dà
{'bad_key2': {'bar', 'foo'},
'bad_key3': {'sad', 'so'},
'good_key2': {'a', 'b', 'c'}}
d1
, d2
ottengoAttributeError: 'dict_values' object has no attribute 'index'
Nel caso in cui tu abbia condizioni diverse per valutare chiavi e valori, la risposta di @ Marcin è la strada da percorrere.
Se hai le stesse condizioni per chiavi e valori, stai meglio con le coppie di costruzione (chiave, valore) in un'espressione di generatore che si alimenta in dict()
:
dict((modify_k(k), modify_v(v)) if condition else (k, v) for k, v in dct.items())
È più facile da leggere e la condizione viene valutata solo una volta per chiave, valore.
Esempio con il prestito di dizionari del set di Cleb:
d = {'key1': {'a', 'b', 'c'}, 'key2': {'foo', 'bar'}, 'key3': {'so', 'sad'}}
Supponiamo di voler aggiungere il suffisso solo keys
con a
in its value
e value
in tal caso si desidera sostituirlo con la lunghezza dell'insieme. Altrimenti, la coppia chiave-valore dovrebbe rimanere invariata.
dict((f"{k}_a", len(v)) if "a" in v else (k, v) for k, v in d.items())
# {'key1_a': 3, 'key2': {'bar', 'foo'}, 'key3': {'sad', 'so'}}
Un altro esempio nell'uso di if / else nella comprensione del dizionario
Sto lavorando su un'applicazione desktop di immissione dati per il mio lavoro d'ufficio ed è comune per tale applicazione di immissione dati ottenere tutte le voci dal widget di input e scaricarle in un dizionario per ulteriori elaborazioni come la convalida o la modifica che dobbiamo restituire dati selezionati dal file ai widget di accesso, ecc.
Il primo round con la codifica tradizionale (8 righe):
entries = {'name': 'Material Name', 'maxt': 'Max Working Temperature', 'ther': {100: 1.1, 200: 1.2}}
a_dic, b_dic = {}, {}
for field, value in entries.items():
if field == 'ther':
for k,v in value.items():
b_dic[k] = v
a_dic[field] = b_dic
else:
a_dic[field] = value
print(a_dic)
“ {'name': 'Material Name', 'maxt': 'Max Working Temperature', 'ther': {100: 1.1, 200: 1.2}}”
Secondo round ho provato a usare la comprensione del dizionario ma il loop è ancora lì (6 righe):
entries = {'name': 'Material Name', 'maxt': 'Max Working Temperature', 'ther': {100: 1.1, 200: 1.2}}
for field, value in entries.items():
if field == 'ther':
b_dic = {k:v for k,v in value.items()}
a_dic[field] = b_dic
else:
a_dic[field] = value
print(a_dic)
“ {'name': 'Material Name', 'maxt': 'Max Working Temperature', 'ther': {100: 1.1, 200: 1.2}}”
Infine, con un'istruzione di comprensione del dizionario di una riga (1 riga):
entries = {'name': 'Material Name', 'maxt': 'Max Working Temperature', 'ther': {100: 1.1, 200: 1.2}}
a_dic = {field:{k:v for k,v in value.items()} if field == 'ther'
else value for field, value in entries.items()}
print(a_dic)
“ {'name': 'Material Name', 'maxt': 'Max Working Temperature', 'ther': {100: 1.1, 200: 1.2}}”
Uso python 3.8.3
dict
è fatto dikey:value
elementi, non stai costruendo undict
qui ma unset
(vedi set letterali ).