222 votes

Nested defaultdict de defaultdict

Existe-t-il un moyen de faire en sorte qu'un defaultdict soit également le défaut pour le defaultdict ? (c'est-à-dire un defaultdict récursif à niveau infini?)

Je veux être capable de faire :

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

Donc, je peux faire x = defaultdict(defaultdict), mais ce n'est que pour un deuxième niveau :

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

Il existe des recettes pour faire cela. Mais est-il possible de le faire simplement en utilisant les arguments normaux de defaultdict ?

Notez que cette question porte sur la façon de créer un defaultdict récursif à niveau infini, donc elle est distincte de Python: defaultdict of defaultdict?, qui traitait de la façon de créer un defaultdict à deux niveaux.

Je finirai probablement par utiliser le motif bunch, mais lorsque j'ai réalisé que je ne savais pas faire cela, cela m'a intéressé.

0voto

Chris Coffee Points 41

Voici une solution similaire à la réponse de @Stanislav qui fonctionne avec le multiprocessus et permet également la terminaison de l'imbrication :

from collections import defaultdict
from functools import partial

class NestedDD(defaultdict):
    def __init__(self, n, *args, **kwargs):
        self.n = n
        factory = partial(build_nested_dd, n=n - 1) if n > 1 else int
        super().__init__(factory, *args, **kwargs)

    def __repr__(self):
        return repr(dict(self))

def build_nested_dd(n):
    return NestedDD(n)

0voto

brocla Points 31

Voici une solution similaire à celle de @Chris W., qui permet d'avoir plus de niveaux possibles. Il permet toujours de spécifier la 'feuille' comme autre chose que defaultdict.

Au lieu d'une lambda, une closure est définie.

Vous pourriez préférer cette méthode parce que

  • la déclaration du defaultdict imbriqué est écrite comme des fonctions imbriquées, ce qui peut le rendre plus lisible.
  • Plus de deux niveaux sont possibles.
  • La dernière feuille peut être: list, set, ...

Voici un exemple.

from collections import defaultdict
import json

def another_defaultdict(factory):
    'retourne une autre couche de defaultdict en tant que fonction factory'
    def layer():
        return defaultdict(factory)  
    return layer

>>> # deux niveaux
>>> d = defaultdict(another_defaultdict(list))

>>> # trois niveaux
>>> d = defaultdict(another_defaultdict(another_defaultdict(list)))

>>> d['Canada']['Alberta'] = ['Calgary', 'Magrath', 'Cardston', 'Lethbridge']
>>> d['France']['Nord'] = ['Dunkirk', 'Croix']
>>> print(json.dumps(d, indent=2))
{
  "Canada": {
    "Alberta": [
      "Calgary",
      "Magrath",
      "Cardston",
      "Lethbridge"
    ]
  },
  "France": {
    "Nord": [
      "Dunkirk",
      "Croix"
    ]
  }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X