Wie kann ich if / else in einem Wörterbuchverständnis verwenden?

138

Gibt es in Python 2.7+ eine Möglichkeit, Folgendes zu erstellen?

{ something_if_true if condition else something_if_false for key, value in dict_.items() }

Ich weiß, dass Sie alles nur mit 'wenn' machen können:

{ something_if_true for key, value in dict_.items() if condition}
diegueus9
quelle
4
Wie von @Marcin gesagt, dictbesteht a aus key:valueElementen, Sie bauen kein dicthier, sondern ein set(siehe Set-Literale ).
mdeous

Antworten:

246

Sie haben es bereits: A if test else Bist ein gültiger Python-Ausdruck. Das einzige Problem mit Ihrem Diktatverständnis, wie gezeigt, besteht darin, dass die Stelle für einen Ausdruck in einem Diktatverständnis zwei Ausdrücke haben muss, die durch einen Doppelpunkt getrennt sind:

{ (some_key if condition else default_key):(something_if_true if condition
          else something_if_false) for key, value in dict_.items() }

Die letzte ifKlausel fungiert als Filter, der sich vom bedingten Ausdruck unterscheidet.

Marcin
quelle
28
Erwähnenswert ist, dass Sie keine If-else-Bedingung sowohl für den Schlüssel als auch für den Wert benötigen. Zum Beispiel {(a if condition else b): value for key, value in dict.items()}wird funktionieren.
Jeremy Weirich
5
@JeremyWeirich Du brauchst kein Wenn-Sonst für eines von beiden, wenn du nicht willst.
Marcin
@Marcin Kann ich nur "if" für den Schlüsselteil und sowohl "if" als auch "else" für den Wertteil verwenden?
nithin11
14

@ Marcins Antwort deckt alles ab, aber für den Fall, dass jemand ein aktuelles Beispiel sehen möchte, füge ich unten zwei hinzu:

Angenommen, Sie haben das folgende Mengenwörterbuch

d = {'key1': {'a', 'b', 'c'}, 'key2': {'foo', 'bar'}, 'key3': {'so', 'sad'}}

und Sie möchten ein neues Wörterbuch erstellen, dessen Schlüssel angeben, ob die Zeichenfolge 'a'in den Werten enthalten ist oder nicht

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()}

was ergibt

{'a_in_values_of_key1': {'a', 'b', 'c'},
 'a_not_in_values_of_key2': {'bar', 'foo'},
 'a_not_in_values_of_key3': {'sad', 'so'}}

Nehmen wir nun an, Sie haben zwei Wörterbücher wie dieses

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'}}

und Sie möchten die Schlüssel d1durch die Schlüssel ersetzen. d2Wenn die jeweiligen Werte identisch sind, können Sie dies tun

# 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()}

was gibt

{'bad_key2': {'bar', 'foo'},
 'bad_key3': {'sad', 'so'},
 'good_key2': {'a', 'b', 'c'}}
Cleb
quelle
für Ihr zweites Beispiel mit d1, d2erhalte ichAttributeError: 'dict_values' object has no attribute 'index'
alancalvitti
@alancalvitti: Danke, dass du darauf hingewiesen hast! Die Lösung war für Python 2 und funktioniert nicht für Python 3; Ich habe auch eine Python 3-Lösung hinzugefügt.
Cleb
3

Falls Sie unterschiedliche Bedingungen für die Bewertung von Schlüsseln und Werten haben, ist die Antwort von @ Marcin der richtige Weg.

Wenn Sie die gleiche Bedingung für Schlüssel und Werte haben, ist es besser, wenn Sie (Schlüssel, Wert) -Tupel in einem Generatorausdruck erstellen, der Folgendes eingibt dict():

dict((modify_k(k), modify_v(v)) if condition else (k, v) for k, v in dct.items())

Es ist einfacher zu lesen und die Bedingung wird nur einmal pro Schlüsselwert bewertet.

Beispiel mit dem Ausleihen von @ Clebs Set-Wörterbuch:

d = {'key1': {'a', 'b', 'c'}, 'key2': {'foo', 'bar'}, 'key3': {'so', 'sad'}}

Angenommen , Sie nur Suffix wollen keysmit ain seine valueund Sie wollen , dass die valuemit der Länge des Satzes in einem solchen Fall ersetzt. Andernfalls sollte das Schlüssel-Wert-Paar unverändert bleiben.

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'}}
Darkonaut
quelle
0

Ein weiteres Beispiel für die Verwendung von if / else im Wörterbuchverständnis

Ich arbeite an einer Dateneingabe-Desktop-Anwendung für meine eigene Büroarbeit, und es ist üblich, dass eine solche Dateneingabe-Anwendung alle Einträge vom Eingabe-Widget abruft und sie zur weiteren Verarbeitung wie Validierung oder Bearbeitung, die wir zurückgeben müssen, in ein Wörterbuch kopiert ausgewählte Daten aus der Datei zurück zu Eintrags-Widgets usw.

Die erste Runde mit traditioneller Codierung (8 Zeilen):

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}}”

Zweite Runde Ich habe versucht, das Wörterbuchverständnis zu verwenden, aber die Schleife ist immer noch da (6 Zeilen):

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}}”

Schließlich mit einer einzeiligen Wörterbuchverständniserklärung (1 Zeile):

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}}”

Ich benutze Python 3.8.3

KokoEfraim
quelle