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.

13voto

Roushan Punkte 3432

Nur Python 3.9+

Die integrierten Operatoren zum Zusammenführen (|) und Aktualisieren (|=) wurden hinzugefügt. dict Klasse.

>>> d = {'spam': 1, 'eggs': 2, 'cheese': 3}
>>> e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}
>>> d | e
{'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}

Die Version mit erweiterter Zuweisung funktioniert an Ort und Stelle:

>>> d |= e
>>> d
{'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}

Siehe PEP 584

12voto

John La Rooy Punkte 278961
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x, z = dict(x), x.update(y) or x
>>> x
{'a': 1, 'b': 2}
>>> y
{'c': 11, 'b': 10}
>>> z
{'a': 1, 'c': 11, 'b': 10}

0 Stimmen

Diese Methode überschreibt x mit seiner Kopie. Wenn x ein Funktionsargument ist, wird dies nicht funktionieren (siehe Beispiel )

12voto

disooqi Punkte 512

In Python 3.9

Basierend auf PEP 584 Mit der neuen Version von Python werden zwei neue Operatoren für Wörterbücher eingeführt: union (|) und in-place union (|=). Sie können | verwenden, um zwei Wörterbücher zusammenzuführen, während |= ein Wörterbuch an Ort und Stelle aktualisiert:

>>> pycon = {2016: "Portland", 2018: "Cleveland"}
>>> europython = {2017: "Rimini", 2018: "Edinburgh", 2019: "Basel"}

>>> pycon | europython
{2016: 'Portland', 2018: 'Edinburgh', 2017: 'Rimini', 2019: 'Basel'}

>>> pycon |= europython
>>> pycon
{2016: 'Portland', 2018: 'Edinburgh', 2017: 'Rimini', 2019: 'Basel'}

Wenn d1 und d2 zwei Wörterbücher sind, dann d1 | d2 tut dasselbe wie {**d1, **d2} . Der Operator | wird zur Berechnung der Vereinigung von Mengen Die Notation dürfte Ihnen also bereits bekannt sein.

Ein Vorteil der Verwendung von | ist, dass es mit verschiedenen wörterbuchähnlichen Typen arbeitet und den Typ durch die Zusammenführung beibehält:

>>> from collections import defaultdict
>>> europe = defaultdict(lambda: "", {"Norway": "Oslo", "Spain": "Madrid"})
>>> africa = defaultdict(lambda: "", {"Egypt": "Cairo", "Zimbabwe": "Harare"})

>>> europe | africa
defaultdict(<function <lambda> at 0x7f0cb42a6700>,
  {'Norway': 'Oslo', 'Spain': 'Madrid', 'Egypt': 'Cairo', 'Zimbabwe': 'Harare'})

>>> {**europe, **africa}
{'Norway': 'Oslo', 'Spain': 'Madrid', 'Egypt': 'Cairo', 'Zimbabwe': 'Harare'}

Sie können ein defaultdict verwenden, wenn Sie fehlende Schlüssel effektiv behandeln wollen. Beachten Sie, dass | bewahrt das Standarddiktat, während {**europe, **africa} nicht.

Es gibt einige Ähnlichkeiten zwischen der | bei Wörterbüchern funktioniert und wie + funktioniert bei Listen. In der Tat, die + Betreiber war ursprünglich vorgeschlagen um auch Wörterbücher zusammenzuführen. Diese Korrespondenz wird noch deutlicher, wenn Sie sich den In-Place-Operator ansehen.

Die grundlegende Verwendung von |= ist es, ein Wörterbuch an Ort und Stelle zu aktualisieren, ähnlich wie bei .update() :

>>> libraries = {
...     "collections": "Container datatypes",
...     "math": "Mathematical functions",
... }
>>> libraries |= {"zoneinfo": "IANA time zone support"}
>>> libraries
{'collections': 'Container datatypes', 'math': 'Mathematical functions',
 'zoneinfo': 'IANA time zone support'}

Beim Zusammenführen von Wörterbüchern mit | müssen beide Wörterbücher von einem geeigneten Wörterbuchtyp sein. Andererseits kann der In-Place-Operator ( |= ) kann mit jeder wörterbuchähnlichen Datenstruktur arbeiten:

>>> libraries |= [("graphlib", "Functionality for graph-like structures")]
>>> libraries
{'collections': 'Container datatypes', 'math': 'Mathematical functions',
 'zoneinfo': 'IANA time zone support',
 'graphlib': 'Functionality for graph-like structures'}

9voto

Alfe Punkte 51658

Ich weiß, dass dies nicht wirklich zu den Besonderheiten der Fragen passt ("one liner"), aber da keine der obigen Antworten gingen in diese Richtung, während sich viele Antworten mit dem Leistungsproblem befassten, wollte ich meine Gedanken dazu beitragen.

Je nach Anwendungsfall ist es möglicherweise nicht notwendig, ein "echtes" zusammengeführtes Wörterbuch aus den gegebenen Eingabewörterbüchern zu erstellen. A siehe das dies tut, könnte in vielen Fällen ausreichend sein, d. h. ein Objekt, das wie das fusionierte Wörterbuch würde, ohne es vollständig zu berechnen. Eine faule Version des zusammengeführten Wörterbuchs, sozusagen.

In Python ist dies recht einfach und kann mit dem am Ende meines Beitrags gezeigten Code durchgeführt werden. Dies vorausgesetzt, wäre die Antwort auf die ursprüngliche Frage:

z = MergeDict(x, y)

Bei der Verwendung dieses neuen Objekts verhält es sich wie ein zusammengeführtes Wörterbuch, aber es hat eine konstante Erstellungszeit und einen konstanten Speicherbedarf, während die ursprünglichen Wörterbücher unberührt bleiben. Seine Erstellung ist wesentlich kostengünstiger als bei den anderen vorgeschlagenen Lösungen.

Wenn Sie das Ergebnis häufig verwenden, stoßen Sie natürlich irgendwann an die Grenze, an der die Erstellung eines echten zusammengeführten Wörterbuchs die schnellere Lösung gewesen wäre. Wie gesagt, es hängt von Ihrem Anwendungsfall ab.

Wenn Sie jemals das Gefühl hatten, dass Sie lieber eine echte fusionierte dict und ruft dann dict(z) produzieren würde (aber natürlich viel teurer als die anderen Lösungen, daher ist dies nur eine Erwähnung wert).

Sie können diese Klasse auch verwenden, um eine Art Copy-on-Write-Wörterbuch zu erstellen:

a = { 'x': 3, 'y': 4 }
b = MergeDict(a)  # we merge just one dict
b['x'] = 5
print b  # will print {'x': 5, 'y': 4}
print a  # will print {'y': 4, 'x': 3}

Hier ist der unkomplizierte Code von MergeDict :

class MergeDict(object):
  def __init__(self, *originals):
    self.originals = ({},) + originals[::-1]  # reversed

  def __getitem__(self, key):
    for original in self.originals:
      try:
        return original[key]
      except KeyError:
        pass
    raise KeyError(key)

  def __setitem__(self, key, value):
    self.originals[0][key] = value

  def __iter__(self):
    return iter(self.keys())

  def __repr__(self):
    return '%s(%s)' % (
      self.__class__.__name__,
      ', '.join(repr(original)
          for original in reversed(self.originals)))

  def __str__(self):
    return '{%s}' % ', '.join(
        '%r: %r' % i for i in self.iteritems())

  def iteritems(self):
    found = set()
    for original in self.originals:
      for k, v in original.iteritems():
        if k not in found:
          yield k, v
          found.add(k)

  def items(self):
    return list(self.iteritems())

  def keys(self):
    return list(k for k, _ in self.iteritems())

  def values(self):
    return list(v for _, v in self.iteritems())

2 Stimmen

Ich habe inzwischen gesehen, dass sich einige Antworten auf eine Klasse namens ChainMap die nur in Python 3 verfügbar ist und die mehr oder weniger das tut, was mein Code tut. Schande über mich, dass ich nicht alles sorgfältig genug gelesen habe. Aber da es das nur für Python 3 gibt, bitte ich Sie, meine Antwort als Beitrag für die Python 2 Benutzer zu verstehen ;-)

5 Stimmen

ChainMap wurde für frühere Pythons zurückportiert: pypi.python.org/pypi/chainmap

7voto

Josh Bode Punkte 3173

Dies ist ein Ausdruck für Python 3.5 oder höher, der Wörterbücher zusammenführt, indem er reduce :

>>> from functools import reduce
>>> l = [{'a': 1}, {'b': 2}, {'a': 100, 'c': 3}]
>>> reduce(lambda x, y: {**x, **y}, l, {})
{'a': 100, 'b': 2, 'c': 3}

Hinweis: Dies funktioniert auch, wenn die Wörterbuchliste leer ist oder nur ein Element enthält.

Für eine effizientere Zusammenführung auf Python 3.9 oder höher, kann die lambda kann direkt ersetzt werden durch operator.ior :

>>> from functools import reduce
>>> from operator import ior
>>> l = [{'a': 1}, {'b': 2}, {'a': 100, 'c': 3}]
>>> reduce(ior, l, {})
{'a': 100, 'b': 2, 'c': 3}

Für Python 3.8 oder weniger kann das folgende als Alternative zu ior :

>>> from functools import reduce
>>> l = [{'a': 1}, {'b': 2}, {'a': 100, 'c': 3}]
>>> reduce(lambda x, y: x.update(y) or x, l, {})
{'a': 100, 'b': 2, 'c': 3}

1 Stimmen

Dies ist sehr ineffizient (so schlecht wie die Zeit proportional zur Anzahl der Tasten im Quadrat). Verwenden Sie operator.ior stattdessen.

0 Stimmen

Danke - ich habe meine Antwort aktualisiert. Ich bin in der Regel nicht zu besorgt über die Effizienz hier, wie ich so etwas für die Zusammenführung der Konfiguration einmal und bei der Initialisierung verwenden würde (auch, ich habe derzeit die Kompatibilität für Python 3.7+ zu halten)

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