更多Pythonic计算重嵌套defaultdict中的东西的方法

时间:2013-05-05 11:43:40

标签: python defaultdict

我的代码目前必须将嵌套dict的内容计入另一个。我有需要用3个值索引的项目,然后计算。所以,在我的循环之前,我像这样初始化嵌套的defaultdict

from collections import defaultdict

type_to_count_dic = defaultdict(
        lambda: defaultdict(
            lambda: defaultdict(int)
        )
    )

这允许我像这样在紧密循环中计算项目:

for a in ...:
    for b in ...:
        for c in ...:
            type_to_count_dic[a][b][c] += 1

我觉得初始化所有defaultdict感觉就像在Java之类的东西中做类型声明一样。做这样的事情是否有更惯用/ Pythonic的方式?

4 个答案:

答案 0 :(得分:8)

from collections import defaultdict

class _defaultdict(defaultdict):
    def __add__(self, other):
        return other

def CountTree():
    return _defaultdict(CountTree)

>>> t = CountTree()
>>> t['a']
defaultdict(<function CountTree at 0x9e5c3ac>, {})
>>> t['a']['b']['c'] += 1
>>> print t['a']['b']['c']
1

答案 1 :(得分:3)

由于你在计算事物,你应该使用一个计数器作为最内在的词典:

import collections
defaultdict = collections.defaultdict
Counter = collections.Counter

x = defaultdict(lambda: defaultdict(Counter))

for a in A:
    for b in B:
        x[a][b].update(C)

使用计数器可以访问有用的方法,例如most_common

根据您对此词典的意图,您可能不需要深层嵌套。相反,您可以使用元组作为密钥。例如,

import collections
import itertools as IT

A = range(2)
B = 'XYZ'
C = 'abc'
x = collections.Counter(IT.product(A, B, C))
print(x)

产量

A = range(2)
B = 'XYZ'
C = 'abc'
x = collections.Counter(IT.product(A, B, C))
print(x)

产量

Counter({(0, 'X', 'c'): 1, (0, 'Z', 'a'): 1, (1, 'Z', 'a'): 1, (1, 'X', 'c'): 1, (1, 'Z', 'b'): 1, (0, 'X', 'b'): 1, (0, 'Y', 'a'): 1, (1, 'Y', 'a'): 1, (0, 'Z', 'c'): 1, (1, 'Z', 'c'): 1, (0, 'X', 'a'): 1, (0, 'Y', 'b'): 1, (1, 'X', 'a'): 1, (1, 'Y', 'b'): 1, (0, 'Z', 'b'): 1, (1, 'Y', 'c'): 1, (1, 'X', 'b'): 1, (0, 'Y', 'c'): 1})

答案 2 :(得分:2)

我假设您只在满足某些条件时添加到每个计数器,或者可能根据条件添加不同的值?否则,每个计数器的值总是为1?

也就是说,我能想到的最简单的解决方案就是创建一个键入三个循环值元组的单个dict。例如:

dict(((a,b,c),1) for a in A for b in B for c in C)

但正如我所说,这只会给你每个柜台1个。您需要使用某些条件或函数调用替换上面表达式中的 1 ,这些函数会根据 a b 的值返回更合适的值em>和 c

答案 3 :(得分:0)

我有类似的需求,并创建了以下内容:

import json

from collections import defaultdict


class NestedDefaultDict(defaultdict):
    def __init__(self, depth, default=int, _root=True):
        self.root = _root
        self.depth = depth
        if depth > 1:
            cur_default = lambda: NestedDefaultDict(depth - 1,
                                                    default,
                                                    False)
        else:
            cur_default = default
        defaultdict.__init__(self, cur_default)

    def __repr__(self):
        if self.root:
            return "NestedDefaultDict(%d): {%s}" % (self.depth,
                                                    defaultdict.__repr__(self))
        else:
            return defaultdict.__repr__(self)


# Quick Example
core_data_type = lambda: [0] * 10
test = NestedDefaultDict(3, core_data_type)
test['hello']['world']['example'][5] += 100
print test
print json.dumps(test)

# Code without custom class.
test = defaultdict(lambda: defaultdict(lambda: defaultdict(core_data_type)))
test['hello']['world']['example'][5] += 100
print test
print json.dumps(test)

如果我最终更新它,我还创建了一个要点:https://gist.github.com/KyleJamesWalker/8573350