defaultdict of defaultdict?
--
Music by Eric Matyas
https://www.soundimage.org
Track title: Luau
--
Chapters
00:00 Question
00:38 Accepted answer (Score 796)
01:24 Answer 2 (Score 57)
02:13 Answer 3 (Score 40)
02:47 Answer 4 (Score 34)
03:04 Thank you
--
Full question
https://stackoverflow.com/questions/5029...
Answer 1 links:
[even better solution using Counter]: http://docs.python.org/2.7/library/colle...
[PyMOTW - Collections - Container data types]: http://www.doughellmann.com/PyMOTW/colle...
[Python Documentation - collections]: http://docs.python.org/library/collectio...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python #collections
#avk47
ACCEPTED ANSWER
Score 869
Yes like this:
defaultdict(lambda: defaultdict(int))
The argument of a defaultdict (in this case is lambda: defaultdict(int)) will be called when you try to access a key that doesn't exist. The return value of it will be set as the new value of this key, which means in our case the value of d[Key_doesnt_exist] will be defaultdict(int).
If you try to access a key from this last defaultdict i.e. d[Key_doesnt_exist][Key_doesnt_exist] it will return 0, which is the return value of the argument of the last defaultdict i.e. int().
ANSWER 2
Score 59
The parameter to the defaultdict constructor is the function which will be called for building new elements. So let's use a lambda !
>>> from collections import defaultdict
>>> d = defaultdict(lambda : defaultdict(int))
>>> print d[0]
defaultdict(<type 'int'>, {})
>>> print d[0]["x"]
0
Since Python 2.7, there's an even better solution using Counter:
>>> from collections import Counter
>>> c = Counter()
>>> c["goodbye"]+=1
>>> c["and thank you"]=42
>>> c["for the fish"]-=5
>>> c
Counter({'and thank you': 42, 'goodbye': 1, 'for the fish': -5})
Some bonus features
>>> c.most_common()[:2]
[('and thank you', 42), ('goodbye', 1)]
For more information see PyMOTW - Collections - Container data types and Python Documentation - collections
ANSWER 3
Score 37
I find it slightly more elegant to use partial:
import functools
dd_int = functools.partial(defaultdict, int)
defaultdict(dd_int)
Of course, this is the same as a lambda.
ANSWER 4
Score 19
For reference, it's possible to implement a generic nested defaultdict factory method through:
from collections import defaultdict
from functools import partial
from itertools import repeat
def nested_defaultdict(default_factory, depth=1):
result = partial(defaultdict, default_factory)
for _ in repeat(None, depth - 1):
result = partial(defaultdict, result)
return result()
The depth defines the number of nested dictionary before the type defined in default_factory is used.
For example:
my_dict = nested_defaultdict(list, 3)
my_dict['a']['b']['c'].append('e')