默认字典的默认字典?

Posted

技术标签:

【中文标题】默认字典的默认字典?【英文标题】:defaultdict of defaultdict? 【发布时间】:2011-06-29 03:11:11 【问题描述】:

有没有办法拥有defaultdict(defaultdict(int)) 以使以下代码正常工作?

for x in stuff:
    d[x.a][x.b] += x.c_int

d 需要临时构建,具体取决于 x.ax.b 元素。

我可以使用:

for x in stuff:
    d[x.a,x.b] += x.c_int

但是我将无法使用:

d.keys()
d[x.a].keys()

【问题讨论】:

查看类似问题What is the best way to implement nested dictionaries in Python?。***关于Autovivification的文章中也有一些可能有用的信息。 【参考方案1】:

是这样的:

defaultdict(lambda: defaultdict(int))

当您尝试访问不存在的密钥时,将调用 defaultdict(在本例中为 lambda: defaultdict(int))的参数。它的返回值将被设置为这个键的新值,这意味着在我们的例子中d[Key_doesnt_exist] 的值将是defaultdict(int)

如果您尝试从最后一个 defaultdict (即d[Key_doesnt_exist][Key_doesnt_exist])访问一个键,它将返回 0,这是最后一个 defaultdict 的参数的返回值,即int()

【讨论】:

效果很好!你能解释一下这个语法背后的原因吗? @Jonathan:是的,当然,当您尝试访问不存在的键并且返回值它将被设置为此键的新值,这意味着在我们的例子中d[Key_dont_exist] 的值将是defaultdict(int),如果您尝试从最后一个默认字典(即d[Key_dont_exist][Key_dont_exist])访问一个键,它将返回 0,即最后一个defaultdictint() 的参数的返回值,希望对您有所帮助。 defaultdict 的参数应该是一个函数。 defaultdict(int) 是字典,lambda: defaultdict(int) 是返回字典的函数。 @has2k1 这是不正确的。 defaultdict 的参数必须是可调用的。 lambda 是可调用的。 @RickyLevi,如果你想让它工作,你可以说:defaultdict(lambda: defaultdict(lambda: defaultdict(int)))【参考方案2】:

defaultdict 构造函数的参数是用于构建新元素的函数。所以让我们使用 lambda !

>>> from collections import defaultdict
>>> d = defaultdict(lambda : defaultdict(int))
>>> print d[0]
defaultdict(<type 'int'>, )
>>> print d[0]["x"]
0

从 Python 2.7 开始,有一个 even better solution using Counter:

>>> from collections import Counter
>>> c = Counter()
>>> c["goodbye"]+=1
>>> c["and thank you"]=42
>>> c["for the fish"]-=5
>>> c
Counter('and thank you': 42, 'goodbye': 1, 'for the fish': -5)

一些额外功能

>>> c.most_common()[:2]
[('and thank you', 42), ('goodbye', 1)]

有关详细信息,请参阅PyMOTW - Collections - Container data types 和 Python Documentation - collections

【讨论】:

只是为了完成这里的循环,您可能希望使用d = defaultdict(lambda : Counter()) 而不是d = defaultdict(lambda : defaultdict(int)) 来专门解决最初提出的问题。 @gumption 你可以只使用d = defaultdict(Counter()) 在这种情况下不需要 lambda @Deb 你有一个小错误 - 删除内括号,所以你传递一个可调用对象而不是 Counter 对象。即:d = defaultdict(Counter)【参考方案3】:

我觉得使用partial 稍微优雅一些​​:

import functools
dd_int = functools.partial(defaultdict, int)
defaultdict(dd_int)

当然,这和 lambda 是一样的。

【讨论】:

Partial 在这里也比 lambda 好,因为它可以递归应用:) 请参阅下面的我的回答,了解通用嵌套 defaultdict 工厂方法。 @Campi 对于递归应用程序,AFAICT 不需要部分【参考方案4】:

以前的答案已经解决了如何制作两级或 n 级defaultdict。在某些情况下,您需要一个无限的:

def ddict():
    return defaultdict(ddict)

用法:

>>> d = ddict()
>>> d[1]['a'][True] = 0.5
>>> d[1]['b'] = 3
>>> import pprint; pprint.pprint(d)
defaultdict(<function ddict at 0x7fcac68bf048>,
            1: defaultdict(<function ddict at 0x7fcac68bf048>,
                            'a': defaultdict(<function ddict at 0x7fcac68bf048>,
                                              True: 0.5),
                             'b': 3))

【讨论】:

我喜欢这个。它非常简单,但非常有用。谢谢! 如何将其用于以下用例:第 n 级需要是 int 或 list @MonsieurBeilto “以前的答案已经解决了如何制作两级或 n 级默认字典”→***.com/a/54266841/695591【参考方案5】:

作为参考,可以通过以下方式实现通用嵌套defaultdict工厂方法:

from collections import defaultdict
from functools import partial
from itertools import repeat


def nested_defaultdict(default_factory, depth=1):
    result = partial(defaultdict, default_factory)
    for _ in repeat(None, depth - 1):
        result = partial(defaultdict, result)
    return result()

深度定义了在使用default_factory 中定义的类型之前嵌套字典的数量。 例如:

my_dict = nested_defaultdict(list, 3)
my_dict['a']['b']['c'].append('e')

【讨论】:

你能举个使用例子吗?没有按我预期的方式工作。 ndd = nested_defaultdict(dict) .... ndd['a']['b']['c']['d'] = 'e' 抛出 KeyError: 'b' 嘿大卫,您需要定义字典的深度,在您的示例 3 中(因为您也将 default_factory 定义为字典。nested_defaultdict(dict, 3) 将为您工作。跨度> 这非常有帮助,谢谢!我注意到的一件事是,这会在 depth=0 创建一个 default_dict,如果在调用时深度未知,则可能并不总是需要这样做。通过在函数顶部添加一行 if not depth: return default_factory() 即可轻松修复,但可能有更优雅的解决方案。【参考方案6】:

其他人已经正确回答了您关于如何使以下内容起作用的问题:

for x in stuff:
    d[x.a][x.b] += x.c_int

另一种方法是使用元组作为键:

d = defaultdict(int)
for x in stuff:
    d[x.a,x.b] += x.c_int
    # ^^^^^^^ tuple key

这种方法的好处是它很简单并且可以很容易地扩展。如果您需要三层深度的映射,只需使用三项元组作为键。

【讨论】:

此解决方案意味着获取所有 d[x.a] 并不简单,因为您需要自省每个键以查看它是否将 x.a 作为元组的第一个元素。 如果你想嵌套 3 层深度,那么只需将其定义为 3 层: d = defaultdict(lambda: defaultdict( lambda: defaultdict(int)))

以上是关于默认字典的默认字典?的主要内容,如果未能解决你的问题,请参考以下文章

collections之有序字典和默认字典

Kali Linux全部默认字典目录+crunch字典生成工具详细使用介绍

Python - 将字典列表附加到嵌套的默认字典时出现关键错误

将默认dict更改为嵌套字典

Python--字典

python字典