2015-06-24 18 views
5

den Wert aus einem verschachtelten Wörterbuch mit Hilfe von Schlüsselpfad holen, hier ist die dict:Nested Wörterbuch Wert von Schlüsselpfad

json = { 
    "app": { 
     "Garden": { 
      "Flowers": { 
       "Red flower": "Rose", 
       "White Flower": "Jasmine", 
       "Yellow Flower": "Marigold" 
      } 
     }, 
     "Fruits": { 
      "Yellow fruit": "Mango", 
      "Green fruit": "Guava", 
      "White Flower": "groovy" 
     }, 
     "Trees": { 
      "label": { 
       "Yellow fruit": "Pumpkin", 
       "White Flower": "Bogan" 
      } 
     } 
    } 

Der Eingangsparameter der Methode ist der Schlüssel Weg mit Punkten getrennt, von Der Schlüsselpfad = "app.Garden.Flowers.white Flower" muss "Jasmine" drucken. Mein Code bis jetzt:

import json 
with open('data.json') as data_file:  
    j = json.load(data_file) 


def find(element, JSON):  
    paths = element.split(".") 
    # print JSON[paths[0]][paths[1]][paths[2]][paths[3]] 
    for i in range(0,len(paths)): 
    data = JSON[paths[i]] 
    # data = data[paths[i+1]] 
    print data 



find('app.Garden.Flowers.White Flower',j) 

Antwort

2

Sehr nah. Sie müssen (wie in Ihrem Kommentar) rekursiv das Haupt-JSON-Objekt durchlaufen. Sie können dies erreichen, indem Sie das Ergebnis des äußersten Schlüssels/Werts speichern und dann den nächsten Schlüssel/Wert usw. verwenden, bis Sie keine Pfade mehr haben.

def find(element, JSON):  
    paths = element.split(".") 
    data = JSON 
    for i in range(0,len(paths)): 
    data = data[paths[i]] 
    print data 

Sie müssen jedoch noch auf KeyErrors achten.

9

Dies ist eine Instanz eines fold. Sie können entweder schreiben prägnant wie folgt aus:

import operator 

def find(element, json): 
    return reduce(operator.getitem, element.split('.'), json) 

oder mehr Pythonically wie folgt aus (weil reduce() auf aufgrund der schlechten Lesbarkeit verpönt):

def find(element, json): 
    keys = element.split('.') 
    rv = json 
    for key in keys: 
     rv = rv[key] 
    return rv 

j = {"app": { 
    "Garden": { 
     "Flowers": { 
      "Red flower": "Rose", 
      "White Flower": "Jasmine", 
      "Yellow Flower": "Marigold" 
     } 
    }, 
    "Fruits": { 
     "Yellow fruit": "Mango", 
     "Green fruit": "Guava", 
     "White Flower": "groovy" 
    }, 
    "Trees": { 
     "label": { 
      "Yellow fruit": "Pumpkin", 
      "White Flower": "Bogan" 
     } 
    } 
}} 
print find('app.Garden.Flowers.White Flower', j) 
+1

Anstatt die Definition einer eigenen item-Getter Funktion Lambda verwenden, können Sie 'importieren und verwenden Unternehmers' operator.getitem'. –

1

Ihr Code auf keine Punkte hängt stark jeder in vorkommenden die Schlüsselnamen, die Sie vielleicht kontrollieren können, aber nicht unbedingt.

Ich würde für eine generische Lösung mit einer Liste von Elementnamen gehen und dann die Liste z. durch eine punktierte Liste von Schlüsselnamen Aufspalten:

class ExtendedDict(dict): 
    """changes a normal dict into one where you can hand a list 
    as first argument to .get() and it will do a recursive lookup 
    result = x.get(['a', 'b', 'c'], default_val) 
    """ 
    def multi_level_get(self, key, default=None): 
     if not isinstance(key, list): 
      return self.get(key, default) 
     # assume that the key is a list of recursively accessible dicts 
     def get_one_level(key_list, level, d): 
      if level >= len(key_list): 
       if level > len(key_list): 
        raise IndexError 
       return d[key_list[level-1]] 
      return get_one_level(key_list, level+1, d[key_list[level-1]]) 

     try: 
      return get_one_level(key, 1, self) 
     except KeyError: 
      return default 

    get = multi_level_get # if you delete this, you can still use the multi_level-get 

Sobald Sie diese Klasse haben, ist es einfach nur Ihre dict zu verwandeln und „Jasmin“ erhalten:

json = { 
     "app": { 
      "Garden": { 
       "Flowers": { 
        "Red flower": "Rose", 
        "White Flower": "Jasmine", 
        "Yellow Flower": "Marigold" 
       } 
      }, 
      "Fruits": { 
       "Yellow fruit": "Mango", 
       "Green fruit": "Guava", 
       "White Flower": "groovy" 
      }, 
      "Trees": { 
       "label": { 
        "Yellow fruit": "Pumpkin", 
        "White Flower": "Bogan" 
       } 
      } 
     } 
    } 

j = ExtendedDict(json) 
print j.get('app.Garden.Flowers.White Flower'.split('.')) 

erhalten Sie:

Jasmine 

Wie bei einem normalen get() aus einem Dict erhalten Sie None, wenn der angegebene Schlüssel (Liste) nirgendwo in der Struktur existiert, und Sie können einen zweiten Parameter als Rückgabe va angeben lue statt None

2

Ein bisschen spät auf die Party, aber ich war in einer ähnlichen Situation und fand diese dpath module. Schön und einfach.

Hoffnung hilft dies jemand anderes :)