python - defaultdict of defaultdict, nested



recursion (5)

C'è un modo per fare di default anche l'impostazione predefinita per defaultdict? IOW, se lo faccio:

x = defaultdict(...stuff...)
x[0][1][0]
{}

È quello che voglio. Probabilmente finirò per usare il modello di mazzo, ma quando ho capito che non sapevo come farlo, mi ha interessato.

Quindi, posso fare:

x = defaultdict(defaultdict)

ma questo è solo un livello:

x[0]
{}
x[0][0]
KeyError: 0

Ci sono ricette che possono farlo. Ma può essere fatto semplicemente usando i normali argomenti defaultdict?

Nota che qualcuno lo ha contrassegnato come un duplicato di Python: defaultdict of defaultdict? , ma questa non è la stessa domanda ... quella domanda era come fare un defaultdict a due livelli; questo è come fare un defaultdict ricorsivo a livello infinito.


Answers

C'è un trucco elegante per farlo:

tree = lambda: defaultdict(tree)

Quindi puoi creare la tua x con x = tree() .


Simile alla soluzione di BrenBarn, ma non contiene il nome dell'albero delle variabili due volte, quindi funziona anche dopo le modifiche al dizionario delle variabili:

tree = (lambda f: f(f))(lambda a: (lambda: defaultdict(a(a))))

Quindi puoi creare ogni nuova x con x = tree() .

Per la versione def , possiamo usare l'ambito di chiusura della funzione per proteggere la struttura dati dalla falla in cui le istanze esistenti smettono di funzionare se il nome tree è in estensione. Sembra questo:

from collections import defaultdict

def tree():
    def the_tree():
        return defaultdict(the_tree)
    return the_tree()

Le altre risposte qui ti dicono come creare un defaultdict che contiene "infinitamente molti" defaultdict , ma non riescono ad affrontare quello che penso possa essere stato il tuo bisogno iniziale, che era semplicemente avere un defaultedict a due profondità.

Forse stavi cercando:

defaultdict(lambda: defaultdict(dict))

I motivi per cui potresti preferire questo costrutto sono:

  • È più esplicito della soluzione ricorsiva e quindi probabilmente più comprensibile per il lettore.
  • Ciò consente alla "foglia" di defaultdict di essere qualcosa di diverso da un dizionario, ad esempio: defaultdict(lambda: defaultdict(list)) o defaultdict(lambda: defaultdict(set))

Per un numero arbitrario di livelli:

def rec_dd():
    return defaultdict(rec_dd)

>>> x = rec_dd()
>>> x['a']['b']['c']['d']
defaultdict(<function rec_dd at 0x7f0dcef81500>, {})
>>> print json.dumps(x)
{"a": {"b": {"c": {"d": {}}}}}

Naturalmente potresti anche farlo con una lambda, ma trovo che lambda sia meno leggibile. In ogni caso assomiglierebbe a questo:

rec_dd = lambda: defaultdict(rec_dd)

0 è il valore condizionale quando questa condizione è vera, il ciclo manterrà l'esecuzione.10 è il valore iniziale. 1 è il modificatore in cui può essere un semplice decremento.

for number in reversed(range(0,10,1)):
print number;




python recursion defaultdict