具有可变深度的多级默认值?

Wei*_*Shi 62 python dictionary

我有一个很大的列表,如:

[A][B1][C1]=1
[A][B1][C2]=2
[A][B2]=3
[D][E][F][G]=4
Run Code Online (Sandbox Code Playgroud)

我想建立一个多级别的词典,如:

A
--B1
-----C1=1
-----C2=1
--B2=3
D
--E
----F
------G=4
Run Code Online (Sandbox Code Playgroud)

我知道,如果我用递归defaultdict我可以写table[A][B1][C1]=1,table[A][B2]=2但如果我硬编码的INSERT语句这只适用.

在解析列表时,我不需要预先调用多少[] table[key1][key2][...].

Hug*_*ter 153

你甚至不用定义一个类就可以做到:

from collections import defaultdict

nested_dict = lambda: defaultdict(nested_dict)
nest = nested_dict()

nest[0][1][2][3][4][5] = 6
Run Code Online (Sandbox Code Playgroud)

  • 这很甜蜜!但是如果我想通过标准(int,list等)工厂初始化叶子怎么样?例如,我想能够说:`table [0] [1] [2] [3] [4] [5] + = 1` (8认同)
  • def nested_dict():返回defaultdict(nested_dict),但我更喜欢lambda版本。它看起来有点神秘;-) (3认同)

Apa*_*ala 17

您的示例说,在任何级别都可以有值,也可以是子元素的字典.这被称为,并且有许多可用的实现.这是一:

from collections import defaultdict
class Tree(defaultdict):
    def __init__(self, value=None):
        super(Tree, self).__init__(Tree)
        self.value = value

root = Tree()
root.value = 1
root['a']['b'].value = 3
print root.value
print root['a']['b'].value
print root['c']['d']['f'].value
Run Code Online (Sandbox Code Playgroud)

输出:

1
3
None
Run Code Online (Sandbox Code Playgroud)

您可以通过在JSON中编写输入并使用json.load它作为嵌套字典的结构来读取它.

  • @Martineau @Jason.`value`实例变量是必要的,因为否则当你直接分配给一个节点时你就会失去孩子(参见我对Jason优雅解决方案的评论).干预`__setitem__`将提供更强大的解决方案,但对于简单的要求来说,这将是一个过于复杂的解决方案. (4认同)

Jas*_*mbs 10

我用dict它定义的子类来做__missing__:

>>> class NestedDict(dict):
...     def __missing__(self, key):
...             self[key] = NestedDict()
...             return self[key]
...
>>> table = NestedDict()
>>> table['A']['B1']['C1'] = 1
>>> table
{'A': {'B1': {'C1': 1}}}
Run Code Online (Sandbox Code Playgroud)

你不能直接用defaultdict来做,因为defaultdict在初始化时期望工厂函数,但是在初始化时,没有办法描述相同的defaultdict.上面的构造与默认dict的作用相同,但由于它是一个命名类(NestedDict),它可以引用自身,因为遇到了丢失的键.也可以将defaultdict和override子类化__init__.

  • @Apalala:实际上,根据OP的示例输入,似乎节点只需要能够保存值**或**子,而不是两者 - 这就是为什么@Jason和我声称你的答案的'value`属性是不必要. (3认同)

Bou*_*egh 6

我认为递归字典的最简单实现就是这个.只有叶节点可以包含值.

# Define recursive dictionary
from collections import defaultdict
tree = lambda: defaultdict(tree)
Run Code Online (Sandbox Code Playgroud)

用法:

# Create instance
mydict = tree()

mydict['a'] = 1
mydict['b']['a'] = 2
mydict['c']
mydict['d']['a']['b'] = 0

# Print
import prettyprint
prettyprint.pp(mydict)
Run Code Online (Sandbox Code Playgroud)

输出:

{
  "a": 1, 
  "b": {
    "a": 1
  }, 
  "c": {},
  "d": {
    "a": {
      "b": 0
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


gab*_*abe 5

这相当于上面的,但避免了 lambda 符号。也许更容易阅读?

def dict_factory():
   return defaultdict(dict_factory)

your_dict = dict_factory()
Run Code Online (Sandbox Code Playgroud)

另外——从评论中——如果你想从现有的字典更新,你可以简单地调用

your_dict[0][1][2].update({"some_key":"some_value"})
Run Code Online (Sandbox Code Playgroud)

为了向字典添加值。