2010-05-09 2 views
82
d3 = dict(d1, **d2) 

Ich verstehe, dass dies das Wörterbuch verbindet. Aber ist es einzigartig? Was ist, wenn d1 denselben Schlüssel wie d2 hat, aber einen anderen Wert? Ich möchte, dass d1 und d2 zusammengeführt werden, aber d1 hat Priorität, wenn es einen doppelten Schlüssel gibt.Wie füge ich Wörterbücher in Python zusammen?

+9

Bitte Seien Sie sich bewusst, dass dieser Trick als Missbrauch des '**' Schlüsselwortarguments gilt, es sei denn, alle Schlüssel von 'd2' sind Zeichenfolgen. Wenn nicht alle Schlüssel von 'd2' Strings sind, schlägt dies in Python 3.2 und in alternativen Implementierungen von Python wie Jython, IronPython und PyPy fehl. Siehe zum Beispiel http://mail.python.org/pipermail/python-dev/2010-April/099459.html. –

+1

mögliches Duplikat von [Wie kann ich zwei Python-Wörterbücher in einem einzigen Ausdruck zusammenführen?] (Http://stackoverflow.com/questions/38987/how-can-i-merge-two-python-dictionaries-in-a-single) -ausdruck) –

Antwort

136

Sie können die .update() Methode verwenden, wenn Sie die ursprüngliche d2 mehr nicht brauchen:

Update, um das Wörterbuch mit den Schlüssel/Wert-Paare aus anderen, überschreiben vorhandene Schlüssel. Zurückgeben None.

Z. B .:

>>> d1 = {'a': 1, 'b': 2} 
>>> d2 = {'b': 1, 'c': 3} 
>>> d2.update(d1) 
>>> d2 
{'a': 1, 'c': 3, 'b': 2} 

Update:

Natürlich können Sie das Wörterbuch zuerst, um kopieren eine neue fusionierte zu erstellen. Dies könnte oder könnte nicht notwendig sein. Wenn Sie zusammengesetzte Objekte (Objekte, die andere Objekte wie Listen oder Klasseninstanzen enthalten) in Ihrem Wörterbuch haben, sollte auch copy.deepcopy berücksichtigt werden.

+1

In diesem Fall sollten d1-Elemente korrekt priorisiert werden, wenn widersprüchliche Schlüssel gefunden werden. –

+0

Falls Sie es noch brauchen, erstellen Sie eine Kopie. d3 = d2.copy() d3.update (d1) aber ich würde gerne sehen, dass d1 + d2 zur Sprache hinzugefügt wird. – stach

+4

d1 + d2 ist problematisch, weil ein Wörterbuch bei Konflikten Priorität haben muss, und es ist nicht besonders offensichtlich, welches. – rjh

36

In Python2,

d1={'a':1,'b':2} 
d2={'a':10,'c':3} 

d1 d2 Überschreibungen:

dict(d2,**d1) 
# {'a': 1, 'c': 3, 'b': 2} 

d2 Überschreibungen d1:

dict(d1,**d2) 
# {'a': 10, 'c': 3, 'b': 2} 

Dieses Verhalten ist nicht nur ein Zufall der Umsetzung ist; es wird in the documentation garantiert:

Wenn ein Schlüssel sowohl im Positions Argument angegeben wird und als Schlüsselwort Argument, der Wert, der mit das Schlüsselwort im Wörterbuch beibehalten wird.

+3

Ihre Beispiele werden in Python 3.2 und in aktuellen Versionen von Jython, PyPy und IronPython fehlschlagen (erzeugen einen TypeError): Für diese Versionen von Python sollten alle Schlüssel dieses Diktats übergeben werden, wenn ein Diktat mit der ** -Schreibweise übergeben wird Sei Saiten. Weitere Informationen finden Sie im python-dev-Thread ab http://mail.python.org/pipermail/python-dev/2010-April/099427.html. –

+0

@Mark: Danke für die Köpfe hoch. Ich habe den Code bearbeitet, um ihn mit Nicht-CPython-Implementierungen kompatibel zu machen. – unutbu

+3

es schlägt fehl, wenn Ihre Schlüssel Tupel von Strings und Zahlen sind. für z. d1 = {(1, 'a'): 1, (1, 'b'): 0,} d2 = {(1, 'a'): 1, (2, 'b'): 2, (2 , 'a'): 1,} – MySchizoBuddy

11

Wenn Sie d1 Priorität in den Konflikten haben, tun:

d3 = d2.copy() 
d3.update(d1) 

Andernfalls Reverse d2 und d1.

1

Meine Lösung ist eine merge Funktion zu definieren. Es ist nicht anspruchsvoll und kostet nur eine Zeile. Hier ist der Code in Python 3.

from functools import reduce 
from operator import or_ 

def merge(*dicts): 
    return { k: reduce(lambda d, x: x.get(k, d), dicts, None) for k in reduce(or_, map(lambda x: x.keys(), dicts), set()) } 

Tests

>>> d = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} 
>>> d_letters = {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'} 
>>> merge(d, d_letters) 
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'} 
>>> merge(d_letters, d) 
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'} 
>>> merge(d) 
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16} 
>>> merge(d_letters) 
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'} 
>>> merge() 
{} 

Es ist für beliebige Anzahl von Wörterbuch Argumente funktioniert. Gab es in diesen Wörterbüchern doppelte Schlüssel, gewinnt der Schlüssel aus dem Wörterbuch ganz rechts in der Argumentliste.

+1

Eine einfache Schleife mit einem '.update' Aufruf (' merged = {} 'gefolgt von' für d in dict: merged.update (d) ') wäre kürzer, lesbarer und effizienter. –

+1

Oder wenn Sie wirklich 'reduce' und' lambda' verwenden möchten, wie wäre es mit 'return reduce (Lambda x, y: x.update (y) oder x, dicts, {})'? –

+0

Sie können Ihren Code in der Shell ausprobieren und sehen, ob er korrekt ist. Ich habe versucht, eine Funktion zu schreiben, die verschiedene Wörterbücher mit derselben Funktionalität verwenden kann.Es ist besser, x.update (y) nicht unter dem Lambda zu verwenden, da es immer _None_ zurückgibt. Und ich versuche, eine allgemeinere Funktion _merge \ _with_ zu schreiben, die verschiedene Anzahl von Wörterbuchargumenten nimmt und doppelte Schlüssel mit der gelieferten Funktion behandelt. Sobald ich fertig bin, poste ich es in einem anderen Thread, wo die Lösung relevanter ist. –

0

Ich glaube, dass, wie oben erwähnt, d2.update(d1) der beste Ansatz ist und dass Sie auch d2 zuerst kopieren können, wenn Sie es noch benötigen.

Obwohl, ich möchte darauf hinweisen, dass dict(d1, **d2) eigentlich eine schlechte Art und Weise ist Wörterbücher im Allgemeinen zu verschmelzen, da Schlüsselwort Argumente müssen Strings sein, so wird es fehlschlagen, wenn Sie eine dict haben, wie:

{ 
    1: 'foo', 
    2: 'bar' 
} 
Verwandte Themen