Python集合计数器用于字典列表

5
我有一个动态增长的数组列表,我希望能够将其中的相同值相加。以下是一个示例:
{"something" : [{"one":"200"}, {"three":"400"}, {"one":"100"}, {"two":"800"} ... ]}

我希望能够将列表中的字典相加。因此,在这种情况下,对于关键字“something”,结果应为:

["one":400, "three": 400, "two": 800]

或类似的东西。我熟悉Python的集合计数器,但由于“something”列表包含字典,它将不起作用(除非我漏掉了什么)。该字典也是动态创建的,因此我无法在没有字典的情况下构建列表。例如:

Counter({'b':3, 'c':4, 'd':5, 'b':2})

通常情况下是可以工作的,但是一旦我尝试添加一个元素,先前的值就会被覆盖。我注意到了其他类似的问题,例如:有没有一种Pythonic的方法来合并两个字典(对于在两个字典中都出现的键,将它们的值相加)?Python中计算列表字典中项目的数量。但是,列表中的对象仍然是字典。

你的结构有些混乱;你有一个单一的外部字典,其值是只有一个键的字典列表?我们需要担心外部字典中是否有许多实际条目?还是我们只是为“something”键添加内部列表中的字典?更完整的输入和输出示例将会更有帮助。 - aruisdante
@aruisdante 对于混淆感到抱歉。这个结构非常令人沮丧,但我除了修改它之外没有控制权。回答你的问题: 1)是的,每个只有一个键。 2)可能会有其他字典,例如Steve Jessop的答案所示。 - Donato Perconti
2个回答

10

我认为这样做可以实现您想要的结果,但我不确定是因为我不知道 "字典也是动态创建的,所以我无法在没有字典的情况下构建列表" 是什么意思。然而:

input = {
    "something" : [{"one":"200"}, {"three":"400"}, {"one":"100"}, {"two":"800"}], 
    "foo" : [{"a" : 100, "b" : 200}, {"a" : 300, "b": 400}],
}

def counterize(x):
    return Counter({k : int(v) for k, v in x.iteritems()})

counts = {
    k : sum((counterize(x) for x in v), Counter()) 
    for k, v in input.iteritems()
}

结果:

{
    'foo': Counter({'b': 600, 'a': 400}), 
    'something': Counter({'two': 800, 'three': 400, 'one': 300})
}

我认为在使用Counter时,与sum一起使用是低效的(就像使用字符串的sum一样低效,所以Guido禁止了它),但我可能错了。无论如何,如果你遇到性能问题,你可以编写一个函数,创建一个Counter对象并反复调用+=update方法:

def makeints(x):
    return {k : int(v) for k, v in x.iteritems()}

def total(seq):
    result = Counter()
    for s in seq:
        result.update(s)
    return result

counts = {k : total(makeints(x) for x in v) for k, v in input.iteritems()}

1
一种方法是按以下方式操作:
from collections import defaultdict

d = {"something" :
     [{"one":"200"}, {"three":"400"}, {"one":"100"}, {"two":"800"}]}

dd = defaultdict(list)

# first get and group values from the original data structure
# and change strings to ints
for inner_dict in d['something']:
    for k,v in inner_dict.items():
        dd[k].append(int(v))


# second. create output dictionary by summing grouped elemetns
# from the first step.
out_dict =  {k:sum(v) for k,v in dd.items()}

print(out_dict)
# {'two': 800, 'one': 300, 'three': 400}

在这里我不使用计数器,而是使用defaultdict。这是一个两步走的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接