2013-04-30 7 views
9

Ho la seguente dict:Aggiunta a un dict utilizzando una lista di stringhe chiave come percorso

aDict = { 
    "a" : { 
     "b" : { 
      "c1" : {}, 
      "c2" : {}, 
     } 
    } 
} 

un secondo dict:

aSecondDict = { 
    "d1" : {}, 
    "d2" : {}, 
    "d3" : {}, 
} 

e un "percorso" tuple:

path = ("a", "b", "c2") 

Ora desidero aggiungere il secondo dict al primo nel percorso fornito dalla tupla:

aResultDict = { 
    "a" : { 
     "b" : { 
      "c1" : {}, 
      "c2" : { 
       "d1" : {}, 
       "d2" : {}, 
       "d3" : {}, 
      }, 
     } 
    } 
} 

Qual è il modo pitonico per raggiungere questo obiettivo?

+1

La prego di correggere i vostri dizionari – jamylak

+0

Grazie martineau :) –

risposta

11

È possibile utilizzare reduce per ottenere il dizionario e dict.update di mettere la nuova roba lì:

reduce(lambda d,key: d[key],path,aDict).update(aSecondDict) 

si può anche ottenere un po 'più intelligente, se si vuole:

reduce(dict.__getitem__,path,aDict).update(aSecondDict) 

Suppongo che si debba notare che i due approcci sono leggermente diversi. Quest'ultimo impone a aDict di contenere solo più dizionari (o sottoclassi dict) mentre il primo consente qualsiasi cosa che abbia un metodo __getitem__ in aDict. As noted in the comments, si potrebbe anche usare:

reduce(dict.get,path,aDict).update(aSecondDict) 

Tuttavia, questa versione genererà un AttributeError se si tenta di attraversare un "link" nel percorso che è inesistente, piuttosto che un KeyError così non mi piace abbastanza. Questo metodo impone anche che ogni valore lungo il percorso sia una sottoclasse dict o dict.

reduce è un builtin per python2.x. A partire da python2.6 è disponibile anche come functools.reduce. Codice che vuole essere compatibile con python3.x dovrebbe cercare di utilizzare functools.reduce come incorporato viene rimosso in python3.x

+0

o 'ridurre (dict.get, percorso, d) ' – jamylak

+0

@jamylak - Giusto. L'inizializzatore va sempre per ultimo. Grazie. – mgilson

+1

Anche se OP vuole una copia può semplicemente usare 'copy.deepcopy' e poi fare questo – jamylak

Problemi correlati