我有一个很大的列表,如:
[A][B1][C1]=1
[A][B1][C2]=2
[A][B2]=3
[D][E][F][G]=4
我想构建一个多级别的词典,如:
A
--B1
-----C1=1
-----C2=1
--B2=3
D
--E
----F
------G=4
我知道如果我使用递归defaultdict,我可以编写table[A][B1][C1]=1
,table[A][B2]=2
,但这只有在我对这些insert语句进行硬编码时才有效。
在解析列表时,我没有事先需要多少[]来调用table[key1][key2][...]
。
答案 0 :(得分:133)
你甚至不用定义一个类就可以做到:
from collections import defaultdict
nested_dict = lambda: defaultdict(nested_dict)
nest = nested_dict()
nest[0][1][2][3][4][5] = 6
答案 1 :(得分:16)
您的示例说,在任何级别都可以有值,也可以是子元素的字典。这称为树,并且有许多可用的实现。这是一个:
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
输出:
1
3
None
您可以通过在JSON中编写输入并使用json.load
将其作为嵌套字典的结构来读取来执行类似操作。
答案 2 :(得分:9)
我会使用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}}}
你无法直接使用defaultdict,因为defaultdict expects the factory function在初始化时,但在初始化时,没有办法描述相同的defaultdict。上面的构造与默认dict的作用相同,但由于它是一个命名类(NestedDict),它可以引用自身,因为遇到了丢失的键。也可以将defaultdict子类化并覆盖__init__
。
答案 3 :(得分:6)
我认为递归字典的最简单实现是这样的。只有叶节点可以包含值。
# Define recursive dictionary
tree = lambda: defaultdict(tree)
用法:
# Create instance
mydict = tree()
tree['a'] = 1
tree['b']['a'] = 2
tree['c']
tree['d']['a']['b'] = 0
# Print
import prettyprint
prettyprint.pp(tree)
输出:
{
"a": 1,
"b": {
"a": 1
},
"c": {},
"d": {
"a": {
"b": 0
}
}
}
答案 4 :(得分:4)
这相当于上面的内容,但避免使用lambda表示法。也许更容易阅读?
def dict_factory():
return defaultdict(dict_factory)
your_dict = dict_factory()
另外 - 从评论中 - 如果你想从现有的词典更新,你可以直接打电话
your_dict[0][1][2].update({"some_key":"some_value"})
为了向字典添加值。
答案 5 :(得分:3)
Dan O' Huiginn在2010年的期刊上发布了一个非常好的解决方案:
http://ohuiginn.net/mt/2010/07/nested_dictionaries_in_python.html
>>> class NestedDict(dict):
... def __getitem__(self, key):
... if key in self: return self.get(key)
... return self.setdefault(key, NestedDict())
>>> eggs = NestedDict()
>>> eggs[1][2][3][4][5]
{}
>>> eggs
{1: {2: {3: {4: {5: {}}}}}}
答案 6 :(得分:2)
允许常规字典初始化的可能性略有不同:
from collections import defaultdict
def superdict(arg=()):
update = lambda obj, arg: obj.update(arg) or obj
return update(defaultdict(superdict), arg)
示例:
>>> d = {"a":1}
>>> sd = superdict(d)
>>> sd["b"]["c"] = 2
答案 7 :(得分:1)
添加到@Hugo
要获得最大深度:
l=lambda x:defaultdict(lambda:l(x-1)) if x>0 else defaultdict(dict)
arr = l(2)
答案 8 :(得分:0)
您可以通过递归defaultdict
来实现。
from collections import defaultdict
def tree():
def the_tree():
return defaultdict(the_tree)
return the_tree()
在闭包(“私有”本地函数作用域)中保护默认工厂名称the_tree
很重要。避免使用单行lambda
版本,该版本由于Python的late binding closures而被错误诊断,而应使用def
来实现。
使用lambda接受的答案存在一个缺陷,即实例必须依赖外部作用域中存在的nested_dict
名称。如果出于某种原因无法解析工厂名称(例如,工厂名称被重新绑定或删除),则先前存在的实例也将被巧妙地破坏:
>>> nested_dict = lambda: defaultdict(nested_dict)
>>> nest = nested_dict()
>>> nest[0][1][2][3][4][6] = 7
>>> del nested_dict
>>> nest[8][9] = 10
# NameError: name 'nested_dict' is not defined
答案 9 :(得分:-4)
拥有table['A']=defaultdict()
。