Wörterbuch: Wie alle Schlüsselpfad aufzulisten, die einen bestimmten Wert enthält?

stimmen
2

Lets sagen, dass ich ein Wörterbuch der Form haben:

d={'geo': {'bgcolor': 'white','lakecolor': 'white','caxis': {'gridcolor': 'white', 'linecolor': 'white',}},
    'title': {'x': 0.05},
    'yaxis': {'automargin': True,'linecolor': 'white','ticks': '','zerolinecolor': 'white','zerolinewidth': 2}
  }

Wie kann man arbeiten Sie Ihren Weg durch diese dict und machen Sie eine Liste von jedem vollständigen Schlüsselpfad, der den Wert enthält 'white'? Von Benutzern jfs in der Post definierte eine Funktion Suche nach einem Wert in einem verschachtelten Wörterbuch Python können Sie überprüfen , ob oder ob nicht 'white'mindestens ein Mal auftritt und gibt auch den Pfad:

# in:
def getpath(nested_dict, value, prepath=()):
    for k, v in nested_dict.items():
        path = prepath + (k,)
        if v == value: # found value
            return path
        elif hasattr(v, 'items'): # v is a dict
            p = getpath(v, value, path) # recursive call
            if p is not None:
                return p
getpath(d,'white')

# out:
('geo', 'bgcolor')

Aber ‚weiß‘ kommt an anderen Orten auch, wie in:

1. d['geo']['lakecolor']

2: d['geo']['caxis']['gridcolor']

3: d['yaxis']['linecolor']

Wie kann ich sicherstellen, dass die Funktion alle Pfade findet?

Ich habe versucht , über die Funktion der Anwendung , bis er zurückkehrt , nonewährend gefunden Pfade Beseitigung einer nach dem anderen, aber das schnell in einen hässlichen Chaos verwandelt.

Vielen Dank für Ihre Anregungen!

Veröffentlicht am 02/12/2019 um 23:54
quelle vom benutzer
In anderen Sprachen...                            


3 antworten

stimmen
1

Wiederkehrende ist , was das Ergebnis unvollständig macht. Statt der Rückkehr, verwenden Sie eine separate Liste Ihre Wege zu verfolgen. Ich verwende Liste cur_listhier, und es am Ende der Schleife zurückkehrt:

d = {
  'geo': {'bgcolor': 'white',
         'caxis': {'gridcolor': 'white', 'linecolor': 'white'},
         'lakecolor': 'white'},
  'title': {'x': 0.05},
  'yaxis': {'automargin': True,
           'linecolor': 'white',
           'ticks': '',
           'zerolinecolor': 'white',
           'zerolinewidth': 2}
}

cur_list = []

def getpath(nested_dict, value, prepath=()):
    for k, v in nested_dict.items():
        path = prepath + (k,)
        if v == value: # found value
            cur_list.append(path)
        elif isinstance(v, dict): # v is a dict
            p = getpath(v, value, path, cur_list) # recursive call
            if p is not None:
                cur_list.append(p)

getpath(d,'white')
print(cur_list)


# RESULT:
# [('geo', 'bgcolor'), ('geo', 'caxis', 'gridcolor'), ('geo', 'caxis', 'linecolor'), ('geo', 'lakecolor'), ('yaxis', 'linecolor'), ('yaxis', 'zerolinecolor')]
Beantwortet am 03/12/2019 um 00:00
quelle vom benutzer

stimmen
1

nur Ihre Funktion transformiert , so dass es eine gibt listund dies nicht tun , returnwenn etwas gefunden wird. Fügen Sie einfach die Liste / erweitern

def getpath(nested_dict, value, prepath=()):
    p = []
    for k, v in nested_dict.items():
        path = prepath + (k,)
        if v == value: # found value
            p.append(path)
        elif hasattr(v, 'items'): # v is a dict
            p += getpath(v, value, path) # recursive call
    return p

mit Eingangsdaten erzeugt diese (Reihenfolge je nach Python Versionen, bei denen Wörterbücher sind ungeordnet):

[('yaxis', 'linecolor'), ('yaxis', 'zerolinecolor'), ('geo', 'lakecolor'), 
('geo', 'caxis', 'linecolor'), ('geo', 'caxis', 'gridcolor'), ('geo', 'bgcolor')]
Beantwortet am 03/12/2019 um 00:00
quelle vom benutzer

stimmen
5

Dies ist ein perfekter Anwendungsfall einen Generator zu schreiben:

def find_paths(haystack, needle):
    if haystack == needle:
        yield ()
    if not isinstance(haystack, dict):
        return
    for key, val in haystack.items():
        for subpath in find_paths(val, needle):
            yield (key, *subpath)

Sie können es wie folgt:

d = {
    'geo': {'bgcolor': 'white','lakecolor': 'white','caxis': {'gridcolor': 'white', 'linecolor': 'white',}},
    'title': {'x': 0.05},
    'yaxis': {'automargin': True,'linecolor': 'white','ticks': '','zerolinecolor': 'white','zerolinewidth': 2}
}

# you can iterate over the paths directly...
for path in find_paths(d, 'white'):
    print('found at path: ', path)

# ...or you can collect them into a list:
paths = list(find_paths(d, 'white'))
print('found at paths: ' + repr(paths))

Der Generator Ansatz hat den Vorteil, dass es nicht um ein Objekt zu erstellen, braucht alle Pfade im Speicher zu halten auf einmal; sie können eins nach dem anderen und sofort verworfen verarbeitet werden. In diesem Fall wären die Speichereinsparungen eher bescheiden, aber in anderen können sie von Bedeutung sein. Auch wenn eine Schleife Iterieren über einen Generator vorzeitig beendet wird, wird der Generator wird nicht weitersuchen, um weitere Wege, die später ohnehin verworfen würden.

Beantwortet am 03/12/2019 um 00:18
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more