Python defaultdict 的嵌套 defaultdict
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19189274/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Nested defaultdict of defaultdict
提问by Corley Brigman
Is there a way to make a defaultdict also be the default for the defaultdict? (i.e. infinite-level recursive defaultdict?)
有没有办法让 defaultdict 也成为 defaultdict 的默认值?(即无限级递归 defaultdict?)
I want to be able to do:
我希望能够做到:
x = defaultdict(...stuff...)
x[0][1][0]
{}
So, I can do x = defaultdict(defaultdict)
, but that's only a second level:
所以,我可以做x = defaultdict(defaultdict)
,但这只是第二级:
x[0]
{}
x[0][0]
KeyError: 0
There are recipes that can do this. But can it be done simply just using the normal defaultdict arguments?
有一些食谱可以做到这一点。但是可以仅使用普通的 defaultdict 参数来完成吗?
Note this is asking how to do an infinite-level recursive defaultdict, so it's distinct to Python: defaultdict of defaultdict?, which was how to do a two-level defaultdict.
请注意,这是在询问如何执行无限级递归 defaultdict,因此它与Python不同:defaultdict of defaultdict?,这是如何做一个两级 defaultdict。
I'll probably just end up using the bunchpattern, but when I realized I didn't know how to do this, it got me interested.
我可能就结束了使用一束模式,但是当我意识到,我不知道如何做到这一点,它让我感兴趣。
采纳答案by Andrew Clark
For an arbitrary number of levels:
对于任意数量的级别:
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": {}}}}}
Of course you could also do this with a lambda, but I find lambdas to be less readable. In any case it would look like this:
当然,您也可以使用 lambda 来执行此操作,但我发现 lambda 的可读性较差。无论如何,它看起来像这样:
rec_dd = lambda: defaultdict(rec_dd)
回答by BrenBarn
There is a nifty trick for doing that:
这样做有一个绝妙的技巧:
tree = lambda: defaultdict(tree)
Then you can create your x
with x = tree()
.
然后你可以x
用x = tree()
.
回答by pts
Similar to BrenBarn's solution, but doesn't contain the name of the variable tree
twice, so it works even after changes to the variable dictionary:
类似于 BrenBarn 的解决方案,但不包含tree
两次变量的名称,因此即使在更改变量字典后它也能工作:
tree = (lambda f: f(f))(lambda a: (lambda: defaultdict(a(a))))
Then you can create each new x
with x = tree()
.
然后你可以x
用x = tree()
.
For the def
version, we can use function closure scope to protect the data structure from the flaw where existing instances stop working if the tree
name is rebound. It looks like this:
对于def
版本,我们可以使用函数闭包作用域来保护数据结构免受tree
名称反弹时现有实例停止工作的缺陷。它看起来像这样:
from collections import defaultdict
def tree():
def the_tree():
return defaultdict(the_tree)
return the_tree()
回答by Chris W.
The other answers here tell you how to create a defaultdict
which contains "infinitely many" defaultdict
, but they fail to address what I think may have been your initial need which was to simply have a two-depth defaultdict.
此处的其他答案告诉您如何创建一个defaultdict
包含 "infinite many" 的内容defaultdict
,但它们未能解决我认为您最初的需求,即简单地拥有两个深度的 defaultdict。
You may have been looking for:
您可能一直在寻找:
defaultdict(lambda: defaultdict(dict))
The reasons why you might prefer this construct are:
您可能更喜欢这种结构的原因是:
- It is more explicit than the recursive solution, and therefore likely more understandable to the reader.
- This enables the "leaf" of the
defaultdict
to be something other than a dictionary, e.g.,:defaultdict(lambda: defaultdict(list))
ordefaultdict(lambda: defaultdict(set))
- 它比递归解决方案更明确,因此读者可能更容易理解。
- 这使 的“叶子”
defaultdict
成为字典以外的东西,例如:defaultdict(lambda: defaultdict(list))
或defaultdict(lambda: defaultdict(set))
回答by Stanislav Tsepa
I would also propose more OOP-styled implementation, which supports infinite nesting as well as properly formatted repr
.
我还会提出更多 OOP 风格的实现,它支持无限嵌套以及正确格式化的repr
.
class NestedDefaultDict(defaultdict):
def __init__(self, *args, **kwargs):
super(NestedDefaultDict, self).__init__(NestedDefaultDict, *args, **kwargs)
def __repr__(self):
return repr(dict(self))
Usage:
用法:
my_dict = NestedDefaultDict()
my_dict['a']['b'] = 1
my_dict['a']['c']['d'] = 2
my_dict['b']
print(my_dict) # {'a': {'b': 1, 'c': {'d': 2}}, 'b': {}}
回答by Dr. XD
here is a recursive function to convert a recursive default dict to a normal dict
这是一个递归函数,用于将递归默认字典转换为普通字典
def defdict_to_dict(defdict, finaldict):
# pass in an empty dict for finaldict
for k, v in defdict.items():
if isinstance(v, defaultdict):
# new level created and that is the new value
finaldict[k] = defdict_to_dict(v, {})
else:
finaldict[k] = v
return finaldict
defdict_to_dict(my_rec_default_dict, {})