2015-10-04 23 views
8

Ho un insieme arbitrariamente profondo di dizionario nidificato:Python: applicare la funzione a valori in dizionario nidificato

x = {'a': 1, 'b': {'c': 6, 'd': 7, 'g': {'h': 3, 'i': 9}}, 'e': {'f': 3}} 

e mi piacerebbe applicare fondamentalmente una funzione per tutti gli interi nei dizionari, così come map , Immagino, ma per i dizionari nidificati.

Quindi: map_nested_dicts(x, lambda v: v + 7) sarebbe il tipo di obiettivo.

Sono bloccato per il modo migliore di memorizzare i livelli dei tasti per riportare il valore modificato nella posizione corretta.

Quale sarebbe il modo migliore/approccio per fare questo essere?

+0

Una soluzione mig ricorsiva lavoro. Esegui un iter sugli oggetti, se un valore è un numero intero, modificalo, se il valore è un dizionario, passalo in una chiamata ricorsiva. – wwii

risposta

13

Visita tutti i valori annidate ricorsivamente:

import collections 

def map_nested_dicts(ob, func): 
    if isinstance(ob, collections.Mapping): 
     return {k: map_nested_dicts(v, func) for k, v in ob.iteritems()} 
    else: 
     return func(ob) 

map_nested_dicts(x, lambda v: v + 7) 
# Creates a new dict object: 
# {'a': 8, 'b': {'c': 13, 'g': {'h': 10, 'i': 16}, 'd': 14}, 'e': {'f': 10}} 

In alcuni casi è desiderato da modificare l'oggetto dict originale (per evitare di ri-crearla):

import collections 

def map_nested_dicts_modify(ob, func): 
    for k, v in ob.iteritems(): 
     if isinstance(v, collections.Mapping): 
      map_nested_dicts_modify(v, func) 
     else: 
      ob[k] = func(v) 

map_nested_dicts_modify(x, lambda v: v + 7) 
# x is now 
# {'a': 8, 'b': {'c': 13, 'g': {'h': 10, 'i': 16}, 'd': 14}, 'e': {'f': 10}} 

Se sei utilizzando Python 3:

  • sostituire.210 con dict.items

  • sostituire import collections con import collections.abc

  • sostituire collections.Mapping con collections.abc.Mapping

+0

Mi chiedevo se il metodo '' 'items''' nella prima funzione potrebbe causare problemi, ma sembra che solo le mappature o le derivate di mappatura utilizzino questo metodo - qualsiasi pensiero? – wwii

+0

@wwii Questa è una sorta di digitazione anatra ... Sì, funzionerà con sottoclassi 'dict's,' dict', 'ChainMap' e altri tipi di mapping. – vaultah

+0

@wwii ma probabilmente hai ragione, ho sostituito il blocco 'try..except' con il controllo' isinstance (ob, collections.Mapping) '. – vaultah

1

Giusto per ampliare la risposta di vaultah, se uno dei vostri elementi può essere una lista, e vuoi per gestire quelli troppo:

import collections 

def map_nested_dicts_modify(ob, func): 
for k, v in ob.iteritems(): 
    if isinstance(v, collections.Mapping): 
     map_nested_dicts_modify(v, func) 
    elif isinstance(v, list): 
     ob[k] = map(func, v) 
    else: 
     ob[k] = func(v) 
Problemi correlati