Question

Est-ce que quelqu'un sait s'il y a une classe standard pour un dictionnaire infiniment emboîtable en Python?

Je me répète trouver ce modèle:

d = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))
d['abc']['def']['xyz'] += 1

Si je veux ajouter « une autre couche » (par exemple d['abc']['def']['xyz']['wrt']), je dois définir une autre imbrication de defaultdicts.

Pour généraliser ce modèle, j'ai écrit une classe simple qui outrepasse __getitem__ pour créer automatiquement le prochain dictionnaire imbriqué.

par exemple.

d = InfiniteDict(('count',0),('total',0))
d['abc']['def']['xyz'].count += 0.24
d['abc']['def']['xyz'].total += 1
d['abc']['def']['xyz']['wrt'].count += 0.143
d['abc']['def']['xyz']['wrt'].total += 1

Cependant, personne ne sait d'une mise en œuvre préexistante de cette idée? J'ai essayé googler, mais je ne suis pas sûr de ce que ce serait appelé.

Était-ce utile?

La solution

Vous pouvez obtenir de defaultdict pour obtenir le comportement souhaité:

class InfiniteDict(defaultdict):
   def __init__(self):
      defaultdict.__init__(self, self.__class__)

class Counters(InfiniteDict):
   def __init__(self):
      InfiniteDict.__init__(self)                                               
      self.count = 0
      self.total = 0

   def show(self):
      print "%i out of %i" % (self.count, self.total)

L'utilisation de cette classe ressemblerait à ceci:

>>> d = Counters()
>>> d[1][2][3].total = 5
>>> d[1][2][3].show()
0 out of 5
>>> d[5].show()
0 out of 0

Autres conseils

Cela donne naturellement à se une définition récursive.

>>> import collections
>>> def nested_dd():
...     return collections.defaultdict(nested_dd)
...
>>> foo = nested_dd()
>>> foo
defaultdict(<function nested_dd at 0x023F0E30>, {})
>>> foo[1][2]=3
>>> foo[1]
defaultdict(<function nested_dd at 0x023F0E30>, {2: 3})
>>> foo[1][2]
3

Je pense que ce one-liner est une solution presque parfaite:

>>> from collections import defaultdict
>>> infinite_defaultdict = lambda: defaultdict(infinite_defaultdict)
>>> d = infinite_defaultdict() 
>>> d['x']['y']['z'] = 10

par Raymond Hettinger sur Twitter ( https://twitter.com/raymondh/status/343823801278140417)

La solution idéale, inspirée par la réponse de STH:

from collections import defaultdict

class InfiniteDict(defaultdict):
   def __init__(self, **kargs):
      defaultdict.__init__(self, lambda: self.__class__(**kargs))
      self.__dict__.update(kargs)

d = InfiniteDict(count=0, total=0)
d['abc']['def'].count += 0.25
d['abc']['def'].total += 1
print d['abc']['def'].count
print d['abc']['def'].total
d['abc']['def']['xyz'].count += 0.789
d['abc']['def']['xyz'].total += 1
print d['abc']['def']['xyz'].count
print d['abc']['def']['xyz'].total

En cas au bout de huit ans, vous pensez toujours sur la façon d'obtenir ce avec une seule ligne:

from collections import defaultdict

t = defaultdict(lambda: defaultdict(t.default_factory))

est proche:

class recursivedefaultdict(defaultdict):
    def __init__(self, attrFactory=int):
        self.default_factory = lambda : type(self)(attrFactory)
        self._attrFactory = attrFactory
    def __getattr__(self, attr):
        newval = self._attrFactory()
        setattr(self, attr, newval)
        return newval

d = recursivedefaultdict(float)
d['abc']['def']['xyz'].count += 0.24  
d['abc']['def']['xyz'].total += 1  

data = [
    ('A','B','Z',1),
    ('A','C','Y',2),
    ('A','C','X',3),
    ('B','A','W',4),
    ('B','B','V',5),
    ('B','B','U',6),
    ('B','D','T',7),
    ]

table = recursivedefaultdict(int)
for k1,k2,k3,v in data:
    table[k1][k2][k3] = v

Il est pas tout à fait ce que vous voulez, puisque le plus profondément niveau imbriqué ne pas votre défaut 0 pour les valeurs « count » ou « totale ».

Modifié: Ah, cela fonctionne maintenant - juste besoin d'ajouter une méthode de __getattr__, et cela fait ce que vous voulez

.

Edit 2: Maintenant, vous pouvez définir d'autres méthodes d'usine pour les attributs, en plus ints. Mais ils doivent tous être du même type, ne peut pas faire un compte et être float totale soit int.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top