Im Grunde ein Wörterbuch mit verschachtelten Listen, Wörterbüchern und Zeichenfolgen beliebiger Tiefe.
Was ist der beste Weg, dies zu durchlaufen, um die Werte jedes “id”-Schlüssels zu extrahieren? Ich möchte das Äquivalent einer XPath-Abfrage wie “//id” erreichen. Der Wert von “id” ist immer ein String.
Aus meinem Beispiel ist die Ausgabe, die ich benötige, im Grunde genommen:
Die meisten Ihrer Lösungen gehen in die Luft, wenn wir bestehen None als Eingang. Legen Sie Wert auf Robustheit? (da dies jetzt als kanonische Frage verwendet wird)
– smci
7. Mai 18 um 5:35 Uhr
Hexerei-Software
Ich fand diese Frage/Antwort sehr interessant, da sie mehrere verschiedene Lösungen für dasselbe Problem bietet. Ich habe all diese Funktionen genommen und sie mit einem komplexen Wörterbuchobjekt getestet. Zwei Funktionen musste ich aus dem Test nehmen, da sie zu viele Fail-Ergebnisse hatten und die Rückgabe von Listen oder Diktaten als Werte nicht unterstützten, was ich für wesentlich halte, da eine Funktion fast vorbereitet sein sollte beliebig Daten kommen.
Also habe ich die anderen Funktionen in 100.000 Iterationen durch die gepumpt timeit Modul und Ausgabe kamen zu folgendem Ergebnis:
Alle Funktionen lieferten das gleiche Ergebnis, aber die Zeitunterschiede sind dramatisch! Die Funktion gen_dict_extract(k,o) ist meine Funktion von den Funktionen hier angepasst, eigentlich ist es ziemlich ähnlich wie die find Funktion von Alfe, mit dem Hauptunterschied, dass ich überprüfe, ob das angegebene Objekt eine iteritems-Funktion hat, falls Strings während der Rekursion übergeben werden:
def gen_dict_extract(key, var):
if hasattr(var,'iteritems'):
for k, v in var.iteritems():
if k == key:
yield v
if isinstance(v, dict):
for result in gen_dict_extract(key, v):
yield result
elif isinstance(v, list):
for d in v:
for result in gen_dict_extract(key, d):
yield result
Diese Variante ist also die schnellste und sicherste der Funktionen hier. Und find_all_items ist unglaublich langsam und weit entfernt vom zweitlangsamsten get_recursivley während der Rest, außer dict_extract, liegt nah beieinander. Die Funktionen fun und keyHole funktionieren nur, wenn Sie nach Saiten suchen.
Interessanter Lernaspekt hier 🙂
Wenn Sie wie ich nach mehreren Schlüsseln suchen möchten, gehen Sie einfach wie folgt vor: (1) Wechseln Sie zu gen_dict_extract(keys, var) (2) setzen for key in keys: als Zeile 2 & Rest einrücken (3) ändern Sie den ersten Ertrag in yield {key: v}
– Bruno Bronosky
20. Februar 17 um 4:22 Uhr
Du vergleichst Äpfel mit Birnen. Das Ausführen einer Funktion, die einen Generator zurückgibt, nimmt weniger Zeit in Anspruch als das Ausführen einer Funktion, die ein fertiges Ergebnis zurückgibt. Probieren Sie timeit aus next(functionname(k, o) für alle Generatorlösungen.
– kaleisin
18. Juli 17 um 13:10 Uhr
hasattr(var, 'items') für Python3
– gobrewers14
8. September 17 um 16:16 Uhr
Haben Sie daran gedacht, die zu entfernen if hasattr Teil für eine Version mit try um die Ausnahme abzufangen, falls der Aufruf fehlschlägt (siehe pastebin.com/ZXvVtV0g für eine mögliche Umsetzung)? Das würde die doppelte Suche des Attributs reduzieren iteritems (einmal für hasattr() und einmal für den Anruf) und damit wahrscheinlich die Laufzeit verkürzen (was Ihnen wichtig erscheint). Habe aber keine Benchmarks gemacht.
– Alfe
9. November 17 um 9:56 Uhr
Denken Sie an alle, die diese Seite jetzt besuchen, nachdem Python 3 übernommen hat iteritems wurde items.
– Mike Williamson
19. Juni 18 um 19:10 Uhr
d = { "id" : "abcde",
"key1" : "blah",
"key2" : "blah blah",
"nestedlist" : [
{ "id" : "qwerty",
"nestednestedlist" : [
{ "id" : "xyz", "keyA" : "blah blah blah" },
{ "id" : "fghi", "keyZ" : "blah blah blah" }],
"anothernestednestedlist" : [
{ "id" : "asdf", "keyQ" : "blah blah" },
{ "id" : "yuiop", "keyW" : "blah" }] } ] }
def fun(d):
if 'id' in d:
yield d['id']
for k in d:
if isinstance(d[k], list):
for i in d[k]:
for j in fun(i):
yield j
Das einzige was ich ändern würde ist for k in d zu for k,value in d.items() mit der anschließenden Verwendung von value anstatt d[k].
– ovgolovin
21. März 2012 um 15:49 Uhr
Danke, das funktioniert super. Sehr geringfügige Änderung erforderlich, da meine Listen sowohl Zeichenfolgen als auch Diktate enthalten können (was ich nicht erwähnt habe), aber ansonsten perfekt.
– Matt Swain
21. März 12 um 15:59 Uhr
Dies passt in einen sehr engen Fall, Sie sind es selbst schuldig, die Antwort von “Hexerei Software” genannt zu berücksichtigen gen_dict_extract
– Bruno Bronosky
20. Februar 17 um 4:24 Uhr
Ich habe den Fehler “TypeError: argument of type ‘NoneType’ is not iterable”
– xiaoshir
15. Juni 18 um 08:11 Uhr
Diese Lösung scheint keine Listen zu unterstützen
– Alex R
26. Februar 19 um 4:49 Uhr
arainchi
d = { "id" : "abcde",
"key1" : "blah",
"key2" : "blah blah",
"nestedlist" : [
{ "id" : "qwerty",
"nestednestedlist" : [
{ "id" : "xyz", "keyA" : "blah blah blah" },
{ "id" : "fghi", "keyZ" : "blah blah blah" }],
"anothernestednestedlist" : [
{ "id" : "asdf", "keyQ" : "blah blah" },
{ "id" : "yuiop", "keyW" : "blah" }] } ] }
def findkeys(node, kv):
if isinstance(node, list):
for i in node:
for x in findkeys(i, kv):
yield x
elif isinstance(node, dict):
if kv in node:
yield node[kv]
for j in node.values():
for x in findkeys(j, kv):
yield x
print(list(findkeys(d, 'id')))
Dieses Beispiel funktionierte mit jedem komplexen Wörterbuch, das ich getestet habe. Gut erledigt.
– Benutzer7548672
4. Februar 19 um 3:04 Uhr
Dies sollte die akzeptierte Antwort sein, es kann Schlüssel finden, die sich in Wörterbüchern befinden, die in einer Liste von Listen usw. verschachtelt sind.
– Anton
10. April 19 um 9:10 Uhr
Dies funktioniert auch in Python3, solange die print-Anweisung am Ende geändert wird. Keine der oben genannten Lösungen funktionierte für eine API-Antwort mit Listen, die in Diktaten verschachtelt sind, die in Listen usw. aufgeführt sind, aber diese funktionierte wunderbar.
– Andy Forceno
27. August 19 um 0:52 Uhr
Alfe
def find(key, value):
for k, v in value.items():
if k == key:
yield v
elif isinstance(v, dict):
for result in find(key, v):
yield result
elif isinstance(v, list):
for d in v:
for result in find(key, d):
yield result
BEARBEITEN: @Anthon bemerkte, dass dies nicht für direkt verschachtelte Listen funktioniert. Wenn Sie dies in Ihrer Eingabe haben, können Sie dies verwenden:
def find(key, value):
for k, v in (value.items() if isinstance(value, dict) else
enumerate(value) if isinstance(value, list) else []):
if k == key:
yield v
elif isinstance(v, (dict, list)):
for result in find(key, v):
yield result
Aber ich denke, die Originalversion ist einfacher zu verstehen, also lasse ich es.
Funktioniert genauso wie die @arainchi-Antwort oben, außerdem gibt es eine Reihe anderer Funktionen verschachtelte Suche Bücherei. Verwenden Sie für das obige Beispiel from nested_lookup import nested_lookup
– Matvei Kruglyak
3. Januar um 22:44 Uhr
Dolan Antenucci
Eine weitere Variante, die den verschachtelten Pfad zu den gefundenen Ergebnissen enthält (Hinweis: Diese Version berücksichtigt keine Listen):
def find_all_items(obj, key, keys=None):
"""
Example of use:
d = {'a': 1, 'b': 2, 'c': {'a': 3, 'd': 4, 'e': {'a': 9, 'b': 3}, 'j': {'c': 4}}}
for k, v in find_all_items(d, 'a'):
print "* {} = {} *".format('->'.join(k), v)
"""
ret = []
if not keys:
keys = []
if key in obj:
out_keys = keys + [key]
ret.append((out_keys, obj[key]))
for k, v in obj.items():
if isinstance(v, dict):
found_items = find_all_items(v, key, keys=(keys+[k]))
ret += found_items
return ret
Funktioniert genauso wie die @arainchi-Antwort oben, außerdem gibt es eine Reihe anderer Funktionen verschachtelte Suche Bücherei. Verwenden Sie für das obige Beispiel from nested_lookup import nested_lookup
– Matvei Kruglyak
3. Januar um 22:44 Uhr
Chris
Ich wollte nur die ausgezeichnete Antwort von @hexerei-software mit wiederholen yield from und Akzeptieren von Top-Level-Listen.
def gen_dict_extract(var, key):
if isinstance(var, dict):
for k, v in var.items():
if k == key:
yield v
if isinstance(v, (dict, list)):
yield from gen_dict_extract(v, key)
elif isinstance(var, list):
for d in var:
yield from gen_dict_extract(d, key)
Hervorragender Mod für die Antwort von @hexerei-software: prägnant und ermöglicht eine Liste von Wörtern! Ich verwende dies zusammen mit den Vorschlägen von @bruno-bronosky in seinen Kommentaren for key in keys. Außerdem habe ich zum 2. hinzugefügt isinstance zu (list, tuple) für sogar mehr Vielfalt. 😉
– Kometengesang
15. Februar 19 um 14:44 Uhr
.
8248500cookie-checkFinden Sie alle Vorkommen eines Schlüssels in verschachtelten Wörterbüchern und Listenyes
Siehe auch: stackoverflow.com/questions/7681301/… stackoverflow.com/a/16508328/42223
– dreftymac
30. Oktober 17 um 19:55 Uhr
Die meisten Ihrer Lösungen gehen in die Luft, wenn wir bestehen
None
als Eingang. Legen Sie Wert auf Robustheit? (da dies jetzt als kanonische Frage verwendet wird)– smci
7. Mai 18 um 5:35 Uhr