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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 13:04:55  来源:igfitidea点击:

Nested defaultdict of defaultdict

pythonrecursiondefaultdict

提问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 xwith x = tree().

然后你可以xx = tree().

回答by pts

Similar to BrenBarn's solution, but doesn't contain the name of the variable treetwice, 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 xwith x = tree().

然后你可以xx = tree().



For the defversion, we can use function closure scope to protect the data structure from the flaw where existing instances stop working if the treename 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 defaultdictwhich 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 defaultdictto be something other than a dictionary, e.g.,: defaultdict(lambda: defaultdict(list))or defaultdict(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, {})