2015-06-24 23 views
5

Prendi il valore da un dizionario nidificato con l'aiuto di percorso della chiave, qui è la dict:valore dizionario nidificate dal percorso della chiave

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" 
      } 
     } 
    } 

Il parametro di ingresso al metodo è il percorso della chiave con i puntini separati, da il percorso chiave = "app.Garden.Flowers.white Flower" deve stampare "Jasmine". Il mio codice finora:

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) 

risposta

2

Molto vicino. Devi (come avevi nel tuo commento) passare in modo ricorsivo attraverso l'oggetto JSON principale. Puoi ottenerlo memorizzando il risultato della chiave/valore più esterno, quindi usarlo per ottenere la chiave/il valore successivo, ecc. Fino a quando non sei fuori dai percorsi.

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

Tuttavia, è necessario prestare attenzione a KeyErrors.

9

Questa è un'istanza di fold. È possibile scrivere in modo conciso come questo:

import operator 

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

O più Pythonically (perché reduce() è visto di buon occhio a causa della scarsa leggibilità) come questo:

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

Invece di definire la propria funzione di elemento getter utilizzando lambda, è possibile importare 'operator' e usare' operator.getitem'. –

1

Il codice dipende fortemente alcuna puntinatura tutti che si verificano in i nomi chiave, che potresti essere in grado di controllare, ma non necessariamente.

Vorrei andare per una soluzione generica utilizzando un elenco di nomi di elementi e quindi generare l'elenco ad es. suddividendo un elenco punteggiata di nomi chiave:

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 

Una volta che avete questa classe è facile trasformare solo il tuo dict e ottenere "Jasmine":

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('.')) 

ti porterà:

Jasmine 

Come con un normale get() da un dict, si ottiene None se la chiave (elenco) specificata non esiste in alcun punto dell'albero e si può specificare un secondo parametro come return va lue invece di None

2

Un po 'tardi alla festa, ma ero in una situazione simile e ho trovato questo dpath module. Bello e facile.

Spero che questo aiuti qualcun altro :)

Problemi correlati