默认字典的默认字典?

发布于 2024-10-17 18:21:39 字数 361 浏览 2 评论 0原文

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

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

d 需要根据 xaxb 元素进行临时构建。

我可以使用:

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

但随后我将无法使用:

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

Is there a way to have a defaultdict(defaultdict(int)) in order to make the following code work?

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

d needs to be built ad-hoc, depending on x.a and x.b elements.

I could use:

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

but then I wouldn't be able to use:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

拍不死你 2024-10-24 18:21:39

是的,就像这样:

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()的参数的返回值

Yes like this:

defaultdict(lambda: defaultdict(int))

The argument of a defaultdict (in this case is lambda: defaultdict(int)) will be called when you try to access a key that doesn't exist. The return value of it will be set as the new value of this key, which means in our case the value of d[Key_doesnt_exist] will be defaultdict(int).

If you try to access a key from this last defaultdict i.e. d[Key_doesnt_exist][Key_doesnt_exist] it will return 0, which is the return value of the argument of the last defaultdict i.e. int().

瑕疵 2024-10-24 18:21:39

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 文档 - 集合

The parameter to the defaultdict constructor is the function which will be called for building new elements. So let's use a lambda !

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

Since Python 2.7, there's an 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})

Some bonus features

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

For more information see PyMOTW - Collections - Container data types and Python Documentation - collections

迷离° 2024-10-24 18:21:39

之前的答案已经解决了如何制作两层或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})})

Previous answers have addressed how to make a two-levels or n-levels defaultdict. In some cases you want an infinite one:

def ddict():
    return defaultdict(ddict)

Usage:

>>> 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})})
沫雨熙 2024-10-24 18:21:39

我发现使用 partial 稍微优雅一些​​:

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

当然,这与 lambda 相同。

I find it slightly more elegant to use partial:

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

Of course, this is the same as a lambda.

云雾 2024-10-24 18:21:39

作为参考,可以通过以下方式实现通用嵌套 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')

For reference, it's possible to implement a generic nested defaultdict factory method through:

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()

The depth defines the number of nested dictionary before the type defined in default_factory is used.
For example:

my_dict = nested_defaultdict(list, 3)
my_dict['a']['b']['c'].append('e')
尬尬 2024-10-24 18:21:39

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

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

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

Others have answered correctly your question of how to get the following to work:

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

An alternative would be to use tuples for keys:

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

The nice thing about this approach is that it is simple and can be easily expanded. If you need a mapping three levels deep, just use a three item tuple for the key.

極樂鬼 2024-10-24 18:21:39

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 方法将其作为工厂函数。因为 defaultdictint 是可pickle的,所有可pickle对象的绑定方法也是如此,这使得结构完全可pickle,无需任何自定义定义或额外的导入。在某些版本的 Python 上,它比等效的 lambda 性能更高(取决于最近的优化工作集中在哪里),但即使不是这样,性能也相当,而且不再多了。冗长,所以即使不关心酸洗,这也是我的首选方法,仅仅是因为这意味着如果/当酸洗变得重要时我不需要改变方法。

defaultdict(lambda: defaultdict(int)) has a flaw, which is that it isn't pickle friendly, thanks to the lambda. While you could define the default function globally, e.g.:

def make_defaultdict_int():
    return defaultdict(int)
dd = defaultdict(make_defaultdict_int)

to work around this, that's rather verbose. Luckily, it's pretty easy to make this work in a pickle-friendly way without that:

dd = defaultdict(defaultdict(int).copy)

That makes a template empty defaultdict(int), and passes a bound copy method from it as the factory function. Because defaultdict and int are pickleable, as are all bound methods of pickleable objects, that renders the structure fully pickleable without any custom definitions or additional imports. On some versions of Python, it's more performant than the equivalent lambda (depending on where the recent optimization efforts have been centered), but even when it isn't, the performance is comparable, and it's no more verbose, so it's my preferred approach even when pickling isn't a concern, simply because it means I don't need to change approaches if/when pickling becomes important.

不爱素颜 2024-10-24 18:21:39
import collections

d = collections.defaultdict(collections.Counter)

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

d = collections.defaultdict(collections.Counter)

for x in stuff:
    d[x.a][x.b] += x.c_int
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文