嵌套的defaultdict of defaultdict

216
有没有办法让defaultdict也成为defaultdict的默认值?(即无限级递归defaultdict?)
我希望能够这样做:
x = defaultdict(...stuff...)
x[0][1][0]
{}

所以,我可以做x = defaultdict(defaultdict),但那只是第二层。
x[0]
{}
x[0][0]
KeyError: 0

有一些配方可以做到这一点。但是只使用普通的defaultdict参数就能简单地做到吗?
请注意,这是在询问如何创建一个无限级递归的defaultdict,因此与“Python:defaultdict of defaultdict?”这个问题是不同的,那个问题是关于如何创建一个两级defaultdict。
我可能最终会使用“bunch”模式,但当我意识到我不知道如何做到这一点时,我对此产生了兴趣。

可能是Python:defaultdict of defaultdict?的重复问题。 - malioboro
2
并不是真的...我在问题中添加了信息来说明原因。虽然那是一个有用的问题。 - Corley Brigman
12个回答

0

@nucklehead的response也可以扩展到处理JSON数组:

def nested_dict(existing=None, **kwargs):
    if existing is None:
        existing = defaultdict()
    if isinstance(existing, list):
        existing = [nested_dict(val) for val in existing]
    if not isinstance(existing, dict):
        return existing
    existing = {key: nested_dict(val) for key, val in existing.items()}
    return defaultdict(nested_dict, existing, **kwargs)

0
这里有一个类似于@Chris W.的解决方案,可以实现更多层级。它允许将“叶子”指定为除了defaultdict之外的其他内容。
不同于使用lambda,这里使用了闭包来定义。
你可能更喜欢这种方法,因为:
  • 嵌套defaultdict的声明被写成了嵌套函数,所以阅读起来更容易。
  • 可以实现超过两个层级。
  • 最后一个叶子可以是列表、集合等等。
以下是一个示例。
from collections import defaultdict
import json

def another_defaultdict(factory):
    'return another layer of defaultdict as a factory function'
    def layer():
        return defaultdict(factory)  
    return layer




>>> # two levels
>>> d = defaultdict(another_defaultdict(list))

>>> # three levels
>>> 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"
    ]
  }
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接