Angenommen, Sie haben ein Wörterbuch wie:
{'a': 1,
'c': {'a': 2,
'b': {'x': 5,
'y' : 10}},
'd': [1, 2, 3]}
Wie würden Sie das in etwas abflachen wie:
{'a': 1,
'c_a': 2,
'c_b_x': 5,
'c_b_y': 10,
'd': [1, 2, 3]}
python
dictionary
Ein Timmes
quelle
quelle
Antworten:
Grundsätzlich müssen Sie auf die gleiche Weise, wie Sie eine verschachtelte Liste reduzieren würden, nur die zusätzliche Arbeit erledigen, um das Diktat nach Schlüssel / Wert zu iterieren, neue Schlüssel für Ihr neues Wörterbuch zu erstellen und das Wörterbuch im letzten Schritt zu erstellen.
quelle
isinstance
durch einentry..except
Block ersetzen , funktioniert dies für jede Zuordnung, auch wenn es nicht von abgeleitet istdict
.collections.MutableMapping
, um es allgemeiner zu machen. Aber für Python <2.6try..except
ist dies wahrscheinlich die beste Option.if isinstance(v, collections.MutableMapping):
zuif v and isinstance(v, collections.MutableMapping):
new_key = parent_key + sep + k if parent_key else k
davon ausgegangen wird, dass Schlüssel immer Zeichenfolgen sind, andernfalls wird sie ausgelöstTypeError: cannot concatenate 'str' and [other] objects
. Sie können dies jedoch beheben, indem Sie einfachk
zu string (str(k)
) zwingen oder Schlüssel zu einem Tupel anstelle eines Strings verketten (Tupel können auch Diktierschlüssel sein).Es gibt zwei wichtige Überlegungen, die das Originalplakat berücksichtigen muss:
{'a_b':{'c':1}, 'a':{'b_c':2}}
würde ergeben{'a_b_c':???}
. Die folgende Lösung umgeht das Problem, indem eine iterierbare Anzahl von Paaren zurückgegeben wird.joinedKey = '_'.join(*keys)
, kostet Sie das O (N ^ 2) Laufzeit. Wenn Sie jedoch bereit sind zu sagennextKey = previousKey+'_'+thisKey
, erhalten Sie O (N) Zeit. Mit der folgenden Lösung können Sie beides tun (da Sie lediglich alle Schlüssel verketten und anschließend nachbearbeiten können).(Leistung ist wahrscheinlich kein Problem, aber ich werde auf den zweiten Punkt eingehen, falls sich jemand anderes darum kümmert: Bei der Implementierung gibt es zahlreiche gefährliche Möglichkeiten. Wenn Sie dies rekursiv tun und nachgeben und wieder nachgeben oder etwas Äquivalentes, das berührt Knoten mehr als einmal (was aus Versehen recht einfach ist), erledigen Sie möglicherweise eher O (N ^ 2) als O (N). Dies liegt daran, dass Sie möglicherweise dann einen Schlüssel berechnen
a
unda_1
danna_1_i
... und dann berechnena
danna_1
danna_1_ii
..., aber eigentlich sollten Sie nicht nocha_1
einmal rechnen müssen . Auch wenn Sie es nicht neu berechnen, ist es genauso schlecht, es erneut zu liefern (ein "Level-by-Level" -Ansatz). Ein gutes Beispiel ist über die Leistung nachdenken auf{1:{1:{1:{1:...(N times)...{1:SOME_LARGE_DICTIONARY_OF_SIZE_N}...}}}}
)Unten ist eine Funktion, die ich geschrieben habe und
flattenDict(d, join=..., lift=...)
die an viele Zwecke angepasst werden kann und die Sie tun können, was Sie wollen. Leider ist es ziemlich schwierig, eine faule Version dieser Funktion zu erstellen, ohne die oben genannten Leistungseinbußen zu verursachen (viele Python-Buildins wie chain.from_iterable sind nicht wirklich effizient, was ich erst nach ausführlichen Tests von drei verschiedenen Versionen dieses Codes festgestellt habe, bevor ich mich entschieden habe dieses).Um besser zu verstehen, was los ist, finden Sie unten ein Diagramm für diejenigen, die mit
reduce
(links) nicht vertraut sind , auch bekannt als "Links falten". Manchmal wird es mit einem Anfangswert anstelle von k0 gezeichnet (nicht Teil der Liste, an die Funktion übergeben). HierJ
ist unserejoin
Funktion. Wir verarbeiten jedes k n mit vorlift(k)
.Dies ist in der Tat dasselbe wie
functools.reduce
, aber wo unsere Funktion dies für alle Schlüsselpfade des Baums tut.Demonstration (die ich sonst in docstring eingefügt hätte):
Performance:
... seufz, glaube nicht, dass einer meine Schuld ist ...
[unwichtiger historischer Hinweis aufgrund von Moderationsproblemen]
In Bezug auf das angebliche Duplikat von Flatten ein Wörterbuch von Wörterbüchern (2 Ebenen tief) von Listen in Python :
Die Lösung dieser Frage kann in Bezug auf diese Frage umgesetzt werden
sorted( sum(flatten(...),[]) )
. Das Gegenteil ist nicht möglich: Zwar können die Werte vonflatten(...)
aus dem angeblichen Duplikat durch Zuordnung eines Akkumulators höherer Ordnung wiederhergestellt werden, die Schlüssel können jedoch nicht wiederhergestellt werden. (Bearbeiten: Es stellt sich auch heraus, dass die Frage des mutmaßlichen Duplikatbesitzers völlig anders ist, da sie sich nur mit Wörterbüchern befasst, die genau 2 Ebenen tief sind, obwohl eine der Antworten auf dieser Seite eine allgemeine Lösung bietet.)quelle
Oder wenn Sie bereits Pandas verwenden, können Sie dies folgendermaßen tun
json_normalize()
:Ausgabe:
quelle
Wenn Sie verwenden,
pandas
ist inpandas.io.json._normalize
1 eine Funktion versteckt ,nested_to_record
die genau dies tut.1 In Pandas-Versionen
0.24.x
und älteren Anwendungenpandas.io.json.normalize
(ohne die_
)quelle
from pandas.io.json._normalize import nested_to_record
. Beachten Sie den Unterstrich (_
) vornormalize
.0.25.x
, ich habe die Antwort aktualisiert. :)Hier ist eine Art "funktionale", "einzeilige" Implementierung. Es ist rekursiv und basiert auf einem bedingten Ausdruck und einem diktierten Verständnis.
Prüfung:
quelle
('hgf',2)
für den 2. Schlüssel in IhrenTypeError
+
Operator unterstützt . Für alles andere müssen Sie sichprefix + separator + k
an den entsprechenden Funktionsaufruf anpassen , um die Objekte zu erstellen.{'a_b':{'c':1}, 'a':{'b_c':2}}
{'name': 'Steven', 'children': [{'name': 'Jessica', 'children': []}, {'name': 'George', 'children': []}]}
Code:
Ergebnisse:
Ich verwende Python3.2, Update für Ihre Version von Python.
quelle
lkey=''
in Ihrer Funktionsdefinition angeben, anstatt die Funktion aufzurufen. Siehe andere Antworten in dieser Hinsicht.Wie wäre es mit einer funktionalen und performanten Lösung in Python3.5?
Dies ist noch performanter:
In Benutzung:
quelle
reduce
es großartig, wenn Sie Wörterbücher reduzieren müssen. Ich habe die Antwort aktualisiert. Sollte jetzt etwas pythonischer aussehen.Dies ist nicht auf Wörterbücher beschränkt, sondern auf jeden Zuordnungstyp, der .items () implementiert. Weiter ist es schneller, da es eine if-Bedingung vermeidet. Trotzdem gehen die Credits an Imran:
quelle
d
es sich nicht um einendict
benutzerdefinierten Zuordnungstyp handelt, der nicht implementiert wirditems
, schlägt Ihre Funktion sofort fehl. Es funktioniert also nicht für jeden Mapping-Typ, sondern nur für diejenigen, die implementiert werdenitems()
.items
? Ich wäre neugierig, einen zu sehen.Meine Python 3.3-Lösung mit Generatoren:
quelle
Einfache Funktion zum Reduzieren verschachtelter Wörterbücher. Für Python 3, ersetzen
.iteritems()
mit.items()
Die Idee / Anforderung war: Holen Sie sich flache Wörterbücher ohne übergeordnete Schlüssel.
Anwendungsbeispiel:
Das Beibehalten von übergeordneten Schlüsseln ist ebenfalls einfach.
quelle
Dies ähnelt sowohl der Antwort von imran als auch von ralu. Es wird kein Generator verwendet, sondern eine Rekursion mit einem Abschluss verwendet:
quelle
_flatten_dict
niemals zurückgegeben wird und auch nicht erwartet wird, dass sie jemals zurückgegeben wird. Es kann stattdessen möglicherweise als Unterfunktion oder als geschlossene Funktion bezeichnet werden.Davouds Lösung ist sehr nett, liefert aber keine zufriedenstellenden Ergebnisse, wenn das verschachtelte Diktat auch Listen von Diktaten enthält, aber sein Code muss für diesen Fall angepasst werden:
quelle
type([])
, um einen Funktionsaufruf für jedes Element der zu vermeidendict
.isinstance(v, list)
stattdessenRekursion nutzen, einfach und lesbar halten:
Anruf ist einfach:
oder
wenn wir das Standardtrennzeichen ändern wollen.
Eine kleine Aufschlüsselung:
Wenn die Funktion zum ersten Mal aufgerufen wird, wird sie nur mit der Übergabe aufgerufen,
dictionary
die abgeflacht werden soll. Deraccumulator
Parameter dient hier zur Unterstützung der Rekursion, die wir später sehen werden. Wir instanziieren alsoaccumulator
zu einem leeren Wörterbuch, in das wir alle verschachtelten Werte aus dem Original einfügendictionary
.Während wir die Werte des Wörterbuchs durchlaufen, erstellen wir für jeden Wert einen Schlüssel. Das
parent_key
Argument giltNone
für den ersten Aufruf, während es für jedes verschachtelte Wörterbuch den Schlüssel enthält, der darauf verweist. Daher stellen wir diesen Schlüssel voran.Wenn der Wert, auf
v
den der Schlüsselk
zeigt, ein Wörterbuch ist, ruft sich die Funktion selbst auf und übergibt das verschachtelte Wörterbuch, dasaccumulator
(das als Referenz übergeben wird, sodass alle daran vorgenommenen Änderungen in derselben Instanz vorgenommen werden) und den Schlüssel,k
damit wir kann den verketteten Schlüssel erstellen. Beachten Sie diecontinue
Aussage. Wir möchten die nächste Zeile außerhalb desif
Blocks überspringen , damit das verschachtelte Wörterbuch nicht in deraccumulator
Unter-Taste landetk
.Was tun wir also, wenn der Wert
v
kein Wörterbuch ist? Legen Sie es einfach unverändert in dieaccumulator
.Sobald wir fertig sind, geben wir einfach das zurück
accumulator
und lassen das ursprünglichedictionary
Argument unberührt.HINWEIS
Dies funktioniert nur mit Wörterbüchern, die Zeichenfolgen als Schlüssel haben. Es funktioniert mit Hash-Objekten, die die
__repr__
Methode implementieren , führt jedoch zu unerwünschten Ergebnissen.quelle
Die obigen Antworten funktionieren wirklich gut. Ich dachte nur, ich würde die Unflatten-Funktion hinzufügen, die ich geschrieben habe:
Hinweis: Dies berücksichtigt nicht '_', das bereits in Schlüsseln vorhanden ist, ähnlich wie die abgeflachten Gegenstücke.
quelle
Hier ist ein Algorithmus für den eleganten Austausch vor Ort. Getestet mit Python 2.7 und Python 3.5. Verwenden des Punktzeichens als Trennzeichen.
Beispiel:
Ausgabe:
Ich habe diesen Code hier zusammen mit der Matching-
unflatten_json
Funktion veröffentlicht.quelle
Wenn Sie ein flach verschachteltes Wörterbuch und eine Liste aller eindeutigen Schlüssel wünschen, ist hier die Lösung:
quelle
quelle
quelle
Ich dachte an eine Unterklasse von UserDict, um die Schlüssel automatisch zu plattieren.
Die Vorteile, dass Schlüssel ohne Überraschung im Handumdrehen oder mithilfe der Standard-Diktatinstanz hinzugefügt werden können:
quelle
Generatoren verwenden:
quelle
type(i).__name__=='dict'
könnte durchtype(i) is dict
oder vielleicht sogar besserisinstance(d, dict)
(oderMapping
/MutableMapping
) ersetzt werden.Verwenden von dict.popitem () in einer einfachen Rekursion wie bei einer verschachtelten Liste:
quelle
Nicht genau das, was das OP verlangt hat, aber viele Leute kommen hierher, um nach Möglichkeiten zu suchen, verschachtelte JSON-Daten aus der realen Welt zu reduzieren, die verschachtelte Json-Objekte und Arrays mit Schlüsselwerten und Json-Objekte in den Arrays usw. enthalten können. JSON enthält keine Tupel, daher müssen wir uns darüber keine Sorgen machen.
Ich habe eine Implementierung des Kommentars zur Aufnahme von Listen durch @roneo auf die Antwort von @Imran gefunden :
https://github.com/ScriptSmith/socialreaper/blob/master/socialreaper/tools.py#L8
Probier es aus:
Und das macht den Job, den ich machen muss: Ich werfe jeden komplizierten JSON darauf und es macht es für mich flacher.
Alle Credits an https://github.com/ScriptSmith .
quelle
Ich habe kürzlich ein Paket namens Cherrypicker geschrieben, um genau diese Dinge zu erledigen, da ich es so oft tun musste!
Ich denke, der folgende Code würde Ihnen genau das geben, wonach Sie suchen:
Sie können das Paket installieren mit:
... und weitere Dokumente und Anleitungen finden Sie unter https://cherrypicker.readthedocs.io .
Andere Methoden sind möglicherweise schneller, aber die Priorität dieses Pakets besteht darin, solche Aufgaben zu vereinfachen . Wenn Sie jedoch eine große Liste von Objekten haben, die abgeflacht werden sollen, können Sie CherryPicker auch anweisen, die Parallelverarbeitung zu verwenden, um die Arbeit zu beschleunigen.
quelle
Ich bevorzuge immer den Zugriff auf
dict
Objekte über.items()
, daher verwende ich zum Reduzieren von Diktaten den folgenden rekursiven Generatorflat_items(d)
. Wenn Sie es nochdict
einmal haben möchten, wickeln Sie es einfach so ein:flat = dict(flat_items(d))
quelle
Variation dieser verschachtelten Wörterbücher reduzieren , Schlüssel mit max_level und benutzerdefiniertem Reduzierer komprimieren .
quelle
Wenn Ihnen rekursive Funktionen nichts ausmachen, finden Sie hier eine Lösung. Ich habe mir auch erlaubt, einen Ausschlussparameter einzuschließen, falls es einen oder mehrere Werte gibt, die Sie beibehalten möchten.
Code:
Verwendung:
Ausgabe:
quelle
Ich habe einige der Lösungen auf dieser Seite ausprobiert - wenn auch nicht alle -, aber diejenigen, die ich ausprobiert habe, konnten die verschachtelte Liste von Diktaten nicht verarbeiten.
Betrachten Sie ein Diktat wie dieses:
Hier ist meine provisorische Lösung:
welches produziert:
Eine provisorische Lösung und nicht perfekt.
HINWEIS:
Es werden keine leeren Wörter wie das
address: {}
k / v-Paar gespeichert .Dicts in verschachtelten Tupeln werden nicht abgeflacht - obwohl es einfach wäre, sie hinzuzufügen, wenn Python-Tupel ähnlich wie Listen funktionieren.
quelle
Verwenden
python-benedict
Sie einfach , es ist eine Diktat-Unterklasse, die viele Funktionen bietet, einschließlich einerflatten
Methode. Es ist möglich, es mit pip zu installieren:pip install python-benedict
https://github.com/fabiocaccamo/python-benedict#flatten
quelle