用于词典列表的Python集合计数器

时间:2015-02-09 02:23:39

标签: python list python-2.7 dictionary collections

我有一个动态增长的数组列表,我想将它们像值一起添加。这是一个例子:

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

我希望能够将列表中的词典加在一起。因此,在这种情况下,对于关键的“某事”,结果将是:

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

或其他相似之处。我熟悉Python的集合计数器,但由于“某事”列表包含dicts,它不起作用(除非我遗漏了一些东西)。 dict也是动态创建的,所以我不能在没有dicts的情况下构建列表。 EG:

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

通常会有效,但只要我尝试添加元素,就会覆盖之前的值。我注意到了其他问题:

Is there any pythonic way to combine two dicts (adding values for keys that appear in both)?

Python count of items in a dictionary of lists

但同样,列表中的对象是dicts。

2 个答案:

答案 0 :(得分:8)

我认为这可以做你想要的,但我不确定,因为我不知道什么" dict也是动态创建的,所以我无法构建列表没有dicts"手段。仍然:

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

我希望sumCounter一起使用是效率低的(与使用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 :(得分: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}

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