Python:defaultdict的defaultdict?

Jon*_*han 287 python collections

有没有办法defaultdict(defaultdict(int))让以下代码工作?

for x in stuff:
    d[x.a][x.b] += x.c_int
Run Code Online (Sandbox Code Playgroud)

d需要根据x.ax.b元素进行临时构建.

我可以用:

for x in stuff:
    d[x.a,x.b] += x.c_int
Run Code Online (Sandbox Code Playgroud)

但后来我无法使用:

d.keys()
d[x.a].keys()
Run Code Online (Sandbox Code Playgroud)

mou*_*uad 523

是这样的:

defaultdict(lambda: defaultdict(int))
Run Code Online (Sandbox Code Playgroud)

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

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

  • @Jonathan:是的,当你试图访问一个不存在的密钥时,将调用`defaultdict`的参数(在这种情况下是`lambda:defaultdict(int)`),它的返回值将是设置为此键的新值,这意味着在我们的例子中,`d [Key_dont_exist]`的值将是`defaultdict(int)`,并且如果您尝试从最后一个defaultdict访问一个键,即`d [Key_dont_exist] [ Key_dont_exist]`它将返回0,这是最后一个``defaultdict``的参数的返回值,即`int()`,希望这是有帮助的. (36认同)
  • @ has2k1这是不正确的.defaultdict的参数需要是可调用的.lambda是可调用的. (27认同)
  • `defaultdict`的参数应该是一个函数.`defaultdict(int)`是一个字典,而`lambda:defaultdict(int)`是返回字典的函数. (25认同)
  • 它很棒!你能解释这种语法背后的理性吗? (7认同)
  • @RickyLevi,如果您想让它正常工作,您可以说:`defaultdict(lambda:defaultdict(lambda:defaultdict(int)))` (2认同)

yan*_*ost 48

defaultdict构造函数的参数是将用于构建新元素的函数.所以让我们用一个lambda!

>>> from collections import defaultdict
>>> d = defaultdict(lambda : defaultdict(int))
>>> print d[0]
defaultdict(<type 'int'>, {})
>>> print d[0]["x"]
0
Run Code Online (Sandbox Code Playgroud)

从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})
Run Code Online (Sandbox Code Playgroud)

一些奖金功能

>>> c.most_common()[:2]
[('and thank you', 42), ('goodbye', 1)]
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅PyMOTW - 集合 - 容器数据类型Python文档 - 集合

  • 只是为了完成这里的圆圈,你会想要使用`d = defaultdict(lambda:Counter())`而不是`d = defaultdict(lambda:defaultdict(int))`来专门解决最初提出的问题. (5认同)
  • @gumption你可以使用`d = defaultdict(Counter())`在这种情况下不需要lambda (3认同)
  • @Deb你有一个小错误 - 删除内括号,所以你传递一个可调用的而不是一个`Counter`对象.那就是:`d = defaultdict(Counter)` (2认同)

Kat*_*iel 28

我觉得它使用起来更优雅partial:

import functools
dd_int = functools.partial(defaultdict, int)
defaultdict(dd_int)
Run Code Online (Sandbox Code Playgroud)

当然,这与lambda相同.

  • Partial 在这里也比 lambda 更好,因为它可以递归应用 :) 请参阅下面的答案,了解通用嵌套 defaultdict 工厂方法。 (2认同)

Clé*_*ent 24

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

def ddict():
    return defaultdict(ddict)
Run Code Online (Sandbox Code Playgroud)

用法:

>>> 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})})
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这个。它非常简单,但非常有用。谢谢! (2认同)

Cam*_*mpi 7

作为参考,可以通过以下方式实现通用的嵌套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()
Run Code Online (Sandbox Code Playgroud)

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

my_dict = nested_defaultdict(list, 3)
my_dict['a']['b']['c'].append('e')
Run Code Online (Sandbox Code Playgroud)


Ste*_*ski 6

其他人已正确回答了您如何使以下工作的问题:

for x in stuff:
    d[x.a][x.b] += x.c_int
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 如果你想深入嵌套3个级别,那么只需将其定义为3个级别:d = defaultdict(lambda:defaultdict(lambda:defaultdict(int))) (5认同)
  • 这个解决方案意味着获取所有d [xa]并不简单,因为您需要内省每个键以查看它是否具有xa作为元组的第一个元素. (4认同)