Ich möchte zwei Wörterbücher zu einem neuen Wörterbuch zusammenführen.
x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}
z = merge(x, y)
>>> z
{'a': 1, 'b': 3, 'c': 4}
Immer wenn ein Schlüssel k
In beiden Wörterbüchern ist nur der Wert vorhanden y[k]
sollte zurückgehalten werden.
In Ihrem Fall können Sie Folgendes tun:
z = dict(list(x.items()) + list(y.items()))
Dies wird, wie Sie es wünschen, das letzte Diktat einfügen z
und machen Sie den Wert für key b
ordnungsgemäß von der Sekunde überschrieben werden (y
) Wert von dict:
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10}
Wenn Sie Python 2 verwenden, können Sie sogar die entfernen list()
Anrufe. So erstellen Sie z:
>>> z = dict(x.items() + y.items())
>>> z
{'a': 1, 'c': 11, 'b': 10}
Wenn Sie die Python-Version 3.9.0a4 oder höher verwenden, können Sie direkt Folgendes verwenden:
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = x | y
print(z)
{'a': 1, 'c': 11, 'b': 10}
Eine andere, prägnantere Option:
z = dict(x, **y)
Notiz: Dies ist eine beliebte Antwort geworden, aber es ist wichtig darauf hinzuweisen, dass if y
keine Zeichenfolgenschlüssel hat, ist die Tatsache, dass dies überhaupt funktioniert, ein Missbrauch eines CPython-Implementierungsdetails, und es funktioniert nicht in Python 3 oder in PyPy, IronPython oder Jython. Auch, Guido ist kein Fan. Daher kann ich diese Technik nicht für aufwärtskompatiblen oder implementierungsübergreifenden portablen Code empfehlen, was wirklich bedeutet, dass sie vollständig vermieden werden sollte.
Dies wird wahrscheinlich keine beliebte Antwort sein, aber Sie möchten dies mit ziemlicher Sicherheit nicht tun. Wenn Sie eine zusammengeführte Kopie wünschen, verwenden Sie copy (bzw tiefe Kopie, je nachdem, was Sie wollen) und dann aktualisieren. Die zwei Codezeilen sind viel besser lesbar – mehr pythonisch – als die einzeilige Erstellung mit .items() + .items(). Explizit ist besser als implizit.
Wenn Sie .items() (vor Python 3.0) verwenden, erstellen Sie außerdem eine neue Liste, die die Elemente aus dem Diktat enthält. Wenn Ihre Wörterbücher groß sind, dann ist das ziemlich viel Overhead (zwei große Listen, die weggeworfen werden, sobald das zusammengeführte Diktat erstellt wird). update() kann effizienter arbeiten, da es das zweite Diktat Element für Element durchlaufen kann.
Bezüglich Zeit:
>>> timeit.Timer("dict(x, **y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.52571702003479
>>> timeit.Timer("temp = x.copy()\ntemp.update(y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.694622993469238
>>> timeit.Timer("dict(x.items() + y.items())", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
41.484580039978027
Meiner Meinung nach lohnt sich die winzige Verlangsamung zwischen den ersten beiden für die Lesbarkeit. Außerdem wurden Schlüsselwortargumente für die Wörterbucherstellung erst in Python 2.3 hinzugefügt, wohingegen copy() und update() in älteren Versionen funktionieren.
In einer Folgeantwort haben Sie nach der relativen Leistung dieser beiden Alternativen gefragt:
z1 = dict(x.items() + y.items())
z2 = dict(x, **y)
Zumindest auf meinem Rechner (ein ziemlich gewöhnlicher x86_64 mit Python 2.5.2) alternativ z2
ist nicht nur kürzer und einfacher, sondern auch deutlich schneller. Sie können dies anhand der selbst überprüfen timeit
Modul, das mit Python geliefert wird.
Beispiel 1: identische Wörterbücher, die 20 aufeinanderfolgende ganze Zahlen auf sich selbst abbilden:
% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z1=dict(x.items() + y.items())'
100000 loops, best of 3: 5.67 usec per loop
% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z2=dict(x, **y)'
100000 loops, best of 3: 1.53 usec per loop
z2
gewinnt um den Faktor 3,5 oder so. Verschiedene Wörterbücher scheinen jedoch zu recht unterschiedlichen Ergebnissen zu führen z2
scheint immer voraus zu sein. (Wenn Sie inkonsistente Ergebnisse für die Dasselbe testen, versuchen, vorbeizukommen -r
mit einer Zahl größer als die Vorgabe 3.)
Beispiel 2: Nicht überlappende Wörterbücher, die 252 kurze Zeichenfolgen auf Ganzzahlen abbilden und umgekehrt:
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z1=dict(x.items() + y.items())'
1000 loops, best of 3: 260 usec per loop
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z2=dict(x, **y)'
10000 loops, best of 3: 26.9 usec per loop
z2
gewinnt etwa um den Faktor 10. Das ist meiner Meinung nach ein ziemlich großer Gewinn!
Nachdem ich diese beiden verglichen hatte, fragte ich mich, ob z1
Die schlechte Leistung von könnte auf den Aufwand für die Erstellung der beiden Elementlisten zurückgeführt werden, was mich wiederum zu der Frage veranlasste, ob diese Variante besser funktionieren könnte:
from itertools import chain
z3 = dict(chain(x.iteritems(), y.iteritems()))
Ein paar schnelle Tests, z
% python -m timeit -s 'from itertools import chain; from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z3=dict(chain(x.iteritems(), y.iteritems()))'
10000 loops, best of 3: 66 usec per loop
lässt mich darauf schließen z3
ist etwas schneller als z1
aber nicht annähernd so schnell wie z2
. Es lohnt sich definitiv nicht, die ganze zusätzliche Eingabe zu machen.
Dieser Diskussion fehlt noch etwas Wichtiges, nämlich ein Leistungsvergleich dieser Alternativen mit der “offensichtlichen” Art der Zusammenführung zweier Listen: die Verwendung von update
Methode. Um zu versuchen, die Dinge mit den Ausdrücken gleichzusetzen, von denen keiner x oder y ändert, werde ich eine Kopie von x erstellen, anstatt es direkt zu ändern, wie folgt:
z0 = dict(x)
z0.update(y)
Ein typisches Ergebnis:
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z0=dict(x); z0.update(y)'
10000 loops, best of 3: 26.9 usec per loop
Mit anderen Worten, z0
Und z2
scheinen im Wesentlichen die gleiche Leistung zu haben. Glauben Sie, dass dies ein Zufall sein könnte? Ich tu nicht….
Ich würde sogar so weit gehen zu behaupten, dass es für reinen Python-Code unmöglich ist, etwas Besseres zu leisten. Und wenn Sie in einem C-Erweiterungsmodul deutlich besser abschneiden, könnten die Python-Leute daran interessiert sein, Ihren Code (oder eine Variation Ihres Ansatzes) in den Python-Kern zu integrieren. Python verwendet dict
an vielen Orten; Die Optimierung des Betriebs ist eine große Sache.
Das könnte man auch so schreiben
z0 = x.copy()
z0.update(y)
wie Tony es tut, aber (nicht überraschend) stellt sich heraus, dass der Unterschied in der Notation keinen messbaren Einfluss auf die Leistung hat. Verwenden Sie, was für Sie richtig aussieht. Natürlich hat er absolut Recht, wenn er darauf hinweist, dass die Version mit zwei Aussagen viel einfacher zu verstehen ist.