defaultdict 的 defaultdict?
- 2025-03-04 08:24:00
- admin 原创
- 41
问题描述:
有没有办法可以defaultdict(defaultdict(int))
使以下代码正常工作?
for x in stuff:
d[x.a][x.b] += x.c_int
d
`x.a需要根据和
x.b`元素进行临时构建。
我可以使用:
for x in stuff:
d[x.a,x.b] += x.c_int
但这样我就不能使用:
d.keys()
d[x.a].keys()
解决方案 1:
是的,就像这样:
defaultdict(lambda: defaultdict(int))
当您尝试访问不存在的键时,将调用a 的参数defaultdict
(在本例中为)。它的返回值将被设置为该键的新值,这意味着在我们的例子中 的值将为。lambda: defaultdict(int)
`d[Key_doesnt_exist]`defaultdict(int)
如果您尝试从最后一个默认字典访问一个键,d[Key_doesnt_exist][Key_doesnt_exist]
它将返回 0,这是最后一个默认字典参数的返回值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 开始,使用 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 - 集合 - 容器数据类型和Python 文档 - 集合
解决方案 3:
先前的答案已经解决了如何制作两级或 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})})
解决方案 4:
我发现使用起来稍微更优雅一些partial
:
import functools
dd_int = functools.partial(defaultdict, int)
defaultdict(dd_int)
当然,这与 lambda 相同。
解决方案 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')
解决方案 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
这种方法的优点在于它很简单,并且可以轻松扩展。如果您需要三级深度映射,只需使用三项元组作为键即可。
解决方案 7:
defaultdict(lambda: defaultdict(int))
有一个缺陷,就是它不友好pickle
,这要归咎于lambda
。虽然你可以全局定义默认函数,例如:
def make_defaultdict_int():
return defaultdict(int)
dd = defaultdict(make_defaultdict_int)
解决这个问题,这太冗长了。幸运的是,pickle
不用这样做,就可以很容易地以友好的方式完成这项工作:
dd = defaultdict(defaultdict(int).copy)
这会使模板为空defaultdict(int)
,并从中传递一个绑定copy
方法作为工厂函数。因为defaultdict
和是int
可腌制的,所有可腌制对象的绑定方法也是如此,这使得结构完全可腌制,而无需任何自定义定义或额外导入。在某些版本的 Python 中,它比等效方法性能更高lambda
(取决于最近的优化工作集中在哪里),但即使不是,性能也是可比的,而且它不会更冗长,所以即使腌制不是问题,这也是我的首选方法,只是因为这意味着当腌制变得重要时,我不需要改变方法。
解决方案 8:
import collections
d = collections.defaultdict(collections.Counter)
for x in stuff:
d[x.a][x.b] += x.c_int