Ich muss mehrere Wörterbücher zusammenführen. Folgendes habe ich zum Beispiel:
dict1 = {1:{"a":{A}}, 2:{"b":{B}}}
dict2 = {2:{"c":{C}}, 3:{"d":{D}}
Mit A
B
C
und D
als Blätter des Baumes, wie{"info1":"value", "info2":"value2"}
Es gibt möglicherweise eine unbekannte Ebene (Tiefe) von Wörterbüchern {2:{"c":{"z":{"y":{C}}}}}
In meinem Fall stellt es eine Verzeichnis- / Dateistruktur dar, wobei Knoten Dokumente sind und Blätter Dateien sind.
Ich möchte sie zusammenführen, um Folgendes zu erhalten:
dict3 = {1:{"a":{A}}, 2:{"b":{B},"c":{C}}, 3:{"d":{D}}}
Ich bin mir nicht sicher, wie ich das mit Python so einfach machen könnte.
python
dictionary
merge
array-merge
fdhex
quelle
quelle
y
auf dasc
Level abgeflacht oder was? Ihr Beispiel ist unvollständig.Antworten:
Dies ist eigentlich ziemlich schwierig - insbesondere, wenn Sie eine nützliche Fehlermeldung wünschen, wenn die Dinge inkonsistent sind, während Sie doppelte, aber konsistente Einträge korrekt akzeptieren (etwas, das hier keine andere Antwort tut ...).
Vorausgesetzt, Sie haben nicht viele Einträge, ist eine rekursive Funktion am einfachsten:
Beachten Sie, dass dies mutiert
a
- der Inhalt vonb
wird hinzugefügta
(was auch zurückgegeben wird). Wenn du behalten willst,a
kannst du es so nennenmerge(dict(a), b)
.agf wies (unten) darauf hin, dass Sie möglicherweise mehr als zwei Diktate haben. In diesem Fall können Sie Folgendes verwenden:
wo alles zu dict1 hinzugefügt wird.
[Anmerkung - Ich habe meine erste Antwort bearbeitet, um das erste Argument zu mutieren. das macht das "Reduzieren" leichter zu erklären]
ps in Python 3 benötigen Sie auch
from functools import reduce
quelle
reduce
oder die entsprechende Schleife stecken , um mit einer beliebigen Anzahl vondict
s anstelle von zwei zu arbeiten. Ich bin mir jedoch nicht sicher, ob dies das tut, was er will (er war sich nicht sicher). Sie landen bei2: {'c': {'z': {'y': {'info1': 'value', 'info2': 'value2'}}}, 'b': {'info1': 'value', 'info2': 'value2'}}
seinem zweiten Beispiel. Ich bin mir nicht sicher, ob er das willz
undy
abgeflacht ist oder nicht.a[key] = a[key] + b[key]
. Danke für die hilfreiche Antwort.copy.deepcopy
.Hier ist eine einfache Möglichkeit, dies mit Generatoren zu tun:
Dies druckt:
quelle
Ein Problem bei dieser Frage ist, dass die Werte des Diktats beliebig komplexe Daten sein können. Basierend auf diesen und anderen Antworten habe ich diesen Code gefunden:
Mein Anwendungsfall ist das Zusammenführen von YAML-Dateien, bei denen ich mich nur mit einer Teilmenge möglicher Datentypen befassen muss. Daher kann ich Tupel und andere Objekte ignorieren. Für mich bedeutet eine vernünftige Zusammenführungslogik
Alles andere und das Unvorhergesehene führt zu einem Fehler.
quelle
isinstance(a, (str, unicode, int, long, float))
wenn nicht?Da dies die kanonische Frage ist (trotz bestimmter Nicht-Allgemeinheiten), biete ich den kanonischen pythonischen Ansatz zur Lösung dieses Problems an.
Einfachster Fall: "Blätter sind verschachtelte Diktate, die in leeren Diktaten enden":
Dies ist der einfachste Fall für eine Rekursion, und ich würde zwei naive Ansätze empfehlen:
Ich glaube, ich würde den zweiten dem ersten vorziehen, aber denke daran, dass der ursprüngliche Zustand des ersten von Anfang an wiederhergestellt werden müsste. Hier ist die Verwendung:
Komplexer Fall: "Blätter sind von jeder anderen Art:"
Wenn sie also in Diktaten enden, ist es ein einfacher Fall, die leeren Enddiktate zusammenzuführen. Wenn nicht, ist es nicht so trivial. Wenn Strings, wie fügst du sie zusammen? Sets können auf ähnliche Weise aktualisiert werden, sodass wir diese Behandlung durchführen können, aber wir verlieren die Reihenfolge, in der sie zusammengeführt wurden. Also ist Ordnung wichtig?
Anstelle von mehr Informationen besteht der einfachste Ansatz darin, ihnen die Standardaktualisierungsbehandlung zu geben, wenn beide Werte keine Diktate sind: dh der Wert des zweiten Diktats überschreibt den ersten, selbst wenn der Wert des zweiten Diktats Keine ist und der Wert des ersten a ist diktieren mit vielen Infos.
Und nun
kehrt zurück
Anwendung auf die ursprüngliche Frage:
Ich musste die geschweiften Klammern um die Buchstaben entfernen und sie in einfache Anführungszeichen setzen, damit dies legitimes Python ist (andernfalls würden sie in Python 2.7+ Literale setzen) sowie eine fehlende Klammer anhängen:
und
rec_merge(dict1, dict2)
kehrt jetzt zurück:Welches passt zum gewünschten Ergebnis der ursprünglichen Frage (nach dem Ändern, zB das
{A}
zu'A'
.)quelle
Basierend auf @andrew cooke. Diese Version verarbeitet verschachtelte Listen von Dikten und bietet auch die Möglichkeit, die Werte zu aktualisieren
quelle
Diese einfache rekursive Prozedur führt ein Wörterbuch in ein anderes zusammen und überschreibt dabei widersprüchliche Schlüssel:
Ausgabe:
quelle
Basierend auf Antworten von @andrew cooke. Es kümmert sich besser um verschachtelte Listen.
quelle
Wenn Sie eine unbekannte Ebene von Wörterbüchern haben, würde ich eine rekursive Funktion vorschlagen:
quelle
Überblick
Der folgende Ansatz unterteilt das Problem einer tiefen Verschmelzung von Diktaten in:
Eine parametrisierte flache Zusammenführungsfunktion
merge(f)(a,b)
, die eine Funktionf
zum Zusammenführen von zwei Diktena
und verwendetb
Eine rekursive Zusammenführungsfunktion
f
, die zusammen mit verwendet werden kannmerge
Implementierung
Eine Funktion zum Zusammenführen von zwei (nicht verschachtelten) Diktaten kann auf viele Arten geschrieben werden. Ich persönlich mag
Eine gute Möglichkeit, eine geeignete rekursive Zusammenführungsfunktion zu definieren,
f
ist die Verwendung von Multipledispatch , mit dem Funktionen definiert werden können, die je nach Art ihrer Argumente auf verschiedenen Pfaden ausgewertet werden.Beispiel
Um zwei verschachtelte Dikte zusammenzuführen, verwenden Sie einfach
merge(f)
z.Anmerkungen:
Die Vorteile dieses Ansatzes sind:
Die Funktion besteht aus kleineren Funktionen, die jeweils eine einzelne Funktion ausführen, wodurch der Code einfacher zu überlegen und zu testen ist
Das Verhalten ist nicht fest codiert, kann jedoch nach Bedarf geändert und erweitert werden, wodurch die Wiederverwendung von Code verbessert wird (siehe Beispiel unten).
Anpassung
Einige Antworten berücksichtigten auch Diktate, die Listen enthalten, z. B. anderer (möglicherweise verschachtelter) Diktate. In diesem Fall möchten Sie möglicherweise die Listen zuordnen und sie basierend auf der Position zusammenführen. Dies kann durch Hinzufügen einer weiteren Definition zur Fusionsfunktion erfolgen
f
:quelle
Sie könnten versuchen, zusammen zu verschmelzen .
Installation
Verwendung
quelle
Es gibt ein kleines Problem mit der Antwort von Andrew Cookes: In einigen Fällen wird das zweite Argument geändert,
b
wenn Sie das zurückgegebene Diktat ändern. Insbesondere liegt es an dieser Zeile:Wenn dies der Fall
b[key]
istdict
, wird es einfach zugewiesena
, was bedeutet, dass alle nachfolgenden Änderungen darandict
sowohla
als auch betreffenb
.Um dies zu beheben, müsste die Zeile durch folgende ersetzt werden:
Wo
clone_dict
ist:Immer noch. Es geht dabei natürlich nicht für
list
,set
und andere Sachen, aber ich hoffe , dass es die Fallen zeigt , wenn zu verschmelzen versuchtdicts
.Und der Vollständigkeit halber hier meine Version, in der Sie sie mehrfach übergeben können
dicts
:quelle
deepcopy
stattclone_dict
?Für den Fall, dass jemand noch einen anderen Ansatz für dieses Problem wünscht , hier ist meine Lösung.
Tugenden : kurz, deklarativ und funktional im Stil (rekursiv, macht keine Mutation).
Möglicher Nachteil : Dies ist möglicherweise nicht die Zusammenführung, nach der Sie suchen. Informationen zur Semantik finden Sie in der Dokumentzeichenfolge.
quelle
Diese Version der Funktion berücksichtigt N Wörterbücher und nur Wörterbücher - es können keine falschen Parameter übergeben werden, oder es wird ein TypeError ausgelöst. Die Zusammenführung selbst berücksichtigt Schlüsselkonflikte. Anstatt Daten aus einem Wörterbuch weiter unten in der Zusammenführungskette zu überschreiben, werden eine Reihe von Werten erstellt und an diese angehängt. Es gehen keine Daten verloren.
Es ist vielleicht nicht das effizienteste auf der Seite, aber es ist das gründlichste und Sie werden keine Informationen verlieren, wenn Sie Ihre 2 zu N Diktate zusammenführen.
Ausgabe: {1: [1, 2], 2: {1: 2, 3: 1}, 4: 4}
quelle
Da dictviews Set-Operationen unterstützen, konnte ich die Antwort von jterrace erheblich vereinfachen.
Jeder Versuch, ein Diktat mit einem Nicht-Diktat zu kombinieren (technisch gesehen ein Objekt mit einer Schlüsselmethode und ein Objekt ohne Schlüsselmethode), löst einen AttributeError aus. Dies umfasst sowohl den ersten Aufruf der Funktion als auch rekursive Aufrufe. Genau das wollte ich, also habe ich es verlassen. Sie können leicht einen AttributeErrors abfangen, der durch den rekursiven Aufruf ausgelöst wird, und dann einen beliebigen Wert liefern.
quelle
Short-n-Sweet:
Dies funktioniert wie die Python-
dict.update
Methode (und baut darauf auf) . Es wird zurückgegebenNone
(Sie können es jederzeit hinzufügen,return d
wenn Sie dies bevorzugen) , wenn das Diktat direkt aktualisiert wirdd
. Mit den Schlüsselnv
werden alle vorhandenen Schlüssel überschriebend
(es wird nicht versucht, den Inhalt des Diktats zu interpretieren).Es funktioniert auch für andere ("diktartige") Zuordnungen.
quelle
Der Code hängt natürlich von Ihren Regeln zur Lösung von Zusammenführungskonflikten ab. Hier ist eine Version, die eine beliebige Anzahl von Argumenten aufnehmen und diese rekursiv zu einer beliebigen Tiefe zusammenführen kann, ohne eine Objektmutation zu verwenden. Es werden die folgenden Regeln verwendet, um Zusammenführungskonflikte zu lösen:
{"foo": {...}}
Vorrang vor{"foo": "bar"}
){"a": 1}
,{"a", 2}
und{"a": 3}
in Ordnung, wird das Ergebnis{"a": 3}
)quelle
Ich hatte zwei Wörterbücher (
a
undb
), die jeweils eine beliebige Anzahl verschachtelter Wörterbücher enthalten konnten. Ich wollte sie rekursiv zusammenführenb
und Vorrang vor ihnen habena
.Ich wollte die verschachtelten Wörterbücher als Bäume betrachten und wollte:
a
damit jeder Pfad zu jedem Blatt inb
dargestellt wirda
a
wenn ein Blatt im entsprechenden Pfad in gefunden wirdb
b
Blattknoten Blätter bleiben.Die vorhandenen Antworten waren für meinen Geschmack etwas kompliziert und ließen einige Details im Regal. Ich habe Folgendes zusammen gehackt, das Unit-Tests für meinen Datensatz besteht.
Beispiel (aus Gründen der Übersichtlichkeit formatiert):
Die Pfade
b
, die beibehalten werden mussten, waren:1 -> 'b' -> 'white'
2 -> 'd' -> 'black'
3 -> 'e'
.a
hatte die einzigartigen und widersprüchlichen Wege von:1 -> 'a' -> 'red'
1 -> 'c' -> 'orange' -> 'dog'
Daher werden sie weiterhin in der zusammengeführten Karte dargestellt.
quelle
Ich habe eine iterative Lösung - funktioniert viel besser mit großen Diktaten und vielen von ihnen (zum Beispiel jsons usw.):
Beachten Sie, dass dies den Wert in d2 verwendet, um d1 zu überschreiben, falls es sich nicht um beide Dikte handelt. (wie bei Python
dict.update()
)Einige Tests:
Ich habe mit ungefähr 1200 Diktaten getestet - diese Methode dauerte 0,4 Sekunden, während die rekursive Lösung ~ 2,5 Sekunden dauerte.
quelle
Dies sollte beim Zusammenführen aller Elemente von
dict2
in helfendict1
:Bitte testen Sie es und sagen Sie uns, ob dies das ist, was Sie wollten.
BEARBEITEN:
Die oben erwähnte Lösung führt nur eine Ebene zusammen, löst jedoch das von OP gegebene Beispiel korrekt. Um mehrere Ebenen zusammenzuführen, sollte die Rekursion verwendet werden.
quelle
for k,v in dict2.iteritems(): dict1.setdefault(k,{}).update(v)
. Aber wie @agf betonte, werden die verschachtelten Dikte nicht zusammengeführt.{'a':'b'}
mit ihnen zu verbinden{'a':{'c':'d'}
).Ich habe Ihre Lösungen getestet und beschlossen, diese in meinem Projekt zu verwenden:
Das Übergeben von Funktionen als Parameter ist der Schlüssel, um die jterrace-Lösung so zu erweitern, dass sie sich wie alle anderen rekursiven Lösungen verhält.
quelle
Der einfachste Weg, den ich mir vorstellen kann, ist:
Ausgabe:
quelle
Ich habe hier eine andere, etwas andere Lösung:
Standardmäßig werden Konflikte zugunsten von Werten aus dem zweiten Diktat gelöst, aber Sie können dies leicht überschreiben. Mit etwas Hexerei können Sie möglicherweise sogar Ausnahmen daraus werfen. :).
quelle
quelle
Hey, da hatte ich auch das gleiche Problem, aber ich dachte über eine Lösung nach und werde es hier posten, falls es auch für andere nützlich ist, im Grunde verschachtelte Wörterbücher zusammenzuführen und auch die Werte hinzuzufügen. Für mich musste ich einige Wahrscheinlichkeiten berechnen, damit dies man hat super gearbeitet:
Mit der obigen Methode können wir zusammenführen:
Ziel = {'6,6': {'6,63': 1}, '63, 4 ': {' 4,4 ': 1},' 4,4 ': {' 4,3 ': 1} , '6,63': {'63, 4 ': 1}}
src = {'5,4': {'4,4': 1}, '5,5': {'5,4': 1}, '4,4': {'4,3': 1} }}
und dies wird: {'5,5': {'5,4': 1}, '5,4': {'4,4': 1}, '6,6': {'6,63' : 1}, '63, 4 ': {' 4,4 ': 1},' 4,4 ': {' 4,3 ': 2},' 6,63 ': {'63, 4': 1 }}
Beachten Sie auch die Änderungen hier:
Ziel = {'6,6': {'6,63': 1}, '6,63': {'63, 4 ': 1}, ' 4,4 ': {' 4,3 ': 1} , '63, 4 ': {' 4,4 ': 1}}
src = {'5,4': {'4,4': 1}, '4,3': {'3,4': 1}, '4,4': {'4,9': 1} , '3,4': {'4,4': 1}, '5,5': {'5,4': 1}}
merge = {'5,4': {'4,4': 1}, '4,3': {'3,4': 1}, '6,63': {'63, 4 ': 1} , '5,5': {'5,4': 1}, '6,6': {'6,63': 1}, '3,4': {'4,4': 1}, ' 63,4 ': {' 4,4 ': 1}, ' 4,4 ': {' 4,3 ': 1,' 4,9 ': 1} }
Vergessen Sie nicht, auch den Import zum Kopieren hinzuzufügen:
quelle
Ausgabe:
quelle
Schauen Sie sich das
toolz
Paket angibt
quelle
Die folgende Funktion führt b zu a zusammen.
quelle
Und noch eine kleine Variation:
Hier ist eine reine Python3-Set-basierte Deep-Update-Funktion. Es aktualisiert verschachtelte Wörterbücher, indem es jeweils eine Ebene durchläuft, und ruft sich selbst auf, um jede nächste Ebene von Wörterbuchwerten zu aktualisieren:
Ein einfaches Beispiel:
quelle
Wie wäre es mit einer anderen Antwort?!? Dieser vermeidet auch Mutationen / Nebenwirkungen:
quelle