7080 Stimmen

Wie führe ich zwei Wörterbücher in einem einzigen Ausdruck zusammen (Vereinigung von Wörterbüchern)?

Ich möchte zwei Wörterbücher zu einem neuen Wörterbuch zusammenführen.

x = {'a': 1, 'b': 2}
y = {'b': 10, 'c': 11}

z = merge(x, y)

>>> z
{'a': 1, 'b': 10, 'c': 11}

使用方法 x.update(y) modifiziert x anstelle eines neuen Wörterbuchs zu erstellen. Ich möchte auch, dass die Konfliktbehandlung des letzten Gewinners von dict.update() auch.

59voto

EMS Punkte 993

Wenn Sie denken, dass Lambdas böse sind, dann lesen Sie nicht weiter. Wie gewünscht, können Sie die schnelle und speichereffiziente Lösung mit einem Ausdruck schreiben:

x = {'a':1, 'b':2}
y = {'b':10, 'c':11}
z = (lambda a, b: (lambda a_copy: a_copy.update(b) or a_copy)(a.copy()))(x, y)
print z
{'a': 1, 'c': 11, 'b': 10}
print x
{'a': 1, 'b': 2}

Wie oben vorgeschlagen, ist die Verwendung von zwei Zeilen oder das Schreiben einer Funktion wahrscheinlich der bessere Weg.

47voto

beardc Punkte 18685

In Python3 wird die items Methode gibt nicht mehr eine Liste zurück sondern vielmehr eine siehe die sich wie eine Menge verhält. In diesem Fall müssen Sie die Mengenvereinigung nehmen, da die Verkettung mit + wird nicht funktionieren:

dict(x.items() | y.items())

Für python3-ähnliches Verhalten in Version 2.7 wird die viewitems Methode sollte anstelle von items :

dict(x.viewitems() | y.viewitems())

Ich bevorzuge diese Schreibweise, da es natürlicher erscheint, sie als eine Operation zur Vereinigung von Mengen und nicht als eine Verkettung (wie der Titel zeigt) zu betrachten.

Editar:

Ein paar weitere Punkte für Python 3. Erstens: Beachten Sie, dass die dict(x, **y) Trick wird in Python 3 nicht funktionieren, es sei denn, die Schlüssel in y sind Zeichenfolgen.

Außerdem: Raymond Hettingers Chainmap Antwort ist ziemlich elegant, da es eine beliebige Anzahl von Dicts als Argumente annehmen kann, aber aus den Unterlagen sieht es so aus, als ob es eine Liste aller Dicts für jede Suche sequentiell durchsucht:

Lookups durchsuchen die zugrunde liegenden Mappings nacheinander, bis ein Schlüssel gefunden wird.

Dies kann zu einer Verlangsamung führen, wenn Sie viele Suchvorgänge in Ihrer Anwendung haben:

In [1]: from collections import ChainMap
In [2]: from string import ascii_uppercase as up, ascii_lowercase as lo; x = dict(zip(lo, up)); y = dict(zip(up, lo))
In [3]: chainmap_dict = ChainMap(y, x)
In [4]: union_dict = dict(x.items() | y.items())
In [5]: timeit for k in union_dict: union_dict[k]
100000 loops, best of 3: 2.15 µs per loop
In [6]: timeit for k in chainmap_dict: chainmap_dict[k]
10000 loops, best of 3: 27.1 µs per loop

Die Suchvorgänge sind also um etwa eine Größenordnung langsamer. Ich bin ein Fan von Chainmap, aber sieht weniger praktisch, wo es viele Lookups sein kann.

38voto

Mathieu Larose Punkte 1170

Zwei Wörterbücher

def union2(dict1, dict2):
    return dict(list(dict1.items()) + list(dict2.items()))

n Wörterbücher

def union(*dicts):
    return dict(itertools.chain.from_iterable(dct.items() for dct in dicts))

sum hat eine schlechte Leistung. Siehe https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/

36voto

reubano Punkte 4501

Einfache Lösung unter Verwendung von itertools, die die Reihenfolge beibehält (letztere Dicts haben Vorrang)

# py2
from itertools import chain, imap
merge = lambda *args: dict(chain.from_iterable(imap(dict.iteritems, args)))

# py3
from itertools import chain
merge = lambda *args: dict(chain.from_iterable(map(dict.items, args)))

Und es ist die Verwendung:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> merge(x, y)
{'a': 1, 'b': 10, 'c': 11}

>>> z = {'c': 3, 'd': 4}
>>> merge(x, y, z)
{'a': 1, 'b': 10, 'c': 3, 'd': 4}

32voto

Claudiu Punkte 215027

Missbrauch führt zu einer Ein-Ausdruck-Lösung für Matthäus' Antwort :

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (lambda f=x.copy(): (f.update(y), f)[1])()
>>> z
{'a': 1, 'c': 11, 'b': 10}

Sie sagten, Sie wollten einen Ausdruck, also habe ich ihn missbraucht lambda um einen Namen zu binden, und Tupel, um die Ein-Ausdruck-Beschränkung von Lambda außer Kraft zu setzen. Fühlen Sie sich frei zu erschaudern.

Sie können dies natürlich auch tun, wenn Ihnen das Kopieren nicht wichtig ist:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (x.update(y), x)[1]
>>> z
{'a': 1, 'b': 10, 'c': 11}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X