Добавьте элементы в списке словарей

У меня есть очень длинный список словарей с индексами строк и целочисленными значениями. Многие ключи являются тем же через словари, хотя не все. Я хочу генерировать один словарь, в котором ключи являются объединением ключей в отдельных словарях, и значения являются суммой всех значений, соответствующих тому ключу в каждом из словарей. (Например, значение для ключевого 'яблока' в объединенном словаре будет суммой значения 'яблока' в первом, плюс сумма значения 'яблока' во втором, и т.д.),

У меня есть следующее, но это является довольно громоздким и берет возрасты для выполнения. Существует ли более простой способ достигнуть того же результата?

comb_dict = {}  
for dictionary in list_dictionaries:  
    for key in dictionary:  
        comb_dict.setdefault(key, 0)  
        comb_dict[key] += dictionary[key]  
return comb_dict
7
задан chimeracoder 29 July 2010 в 19:20
поделиться

4 ответа

Вот несколько тестов, которые предполагают, что f2 (см. Ниже) может быть улучшением. f2 использует iteritems , что позволяет избежать лишнего поиска по словарю во внутреннем цикле:

import collections
import string
import random

def random_dict():
    n=random.randint(1,26)
    keys=list(string.letters)
    random.shuffle(keys)
    keys=keys[:n]
    values=[random.randint(1,100) for _ in range(n)]    
    return dict(zip(keys,values))

list_dictionaries=[random_dict() for x in xrange(100)]

def f1(list_dictionaries):
    comb_dict = {}  
    for dictionary in list_dictionaries:  
        for key in dictionary:  
            comb_dict.setdefault(key, 0)  
            comb_dict[key] += dictionary[key]  
    return comb_dict

def f2(list_dictionaries):    
    comb_dict = collections.defaultdict(int)
    for dictionary in list_dictionaries:  
        for key,value in dictionary.iteritems():  
            comb_dict[key] += value
    return comb_dict

def union( dict_list ):
    all_keys = set()
    for d in dict_list:
        for k in d:
            all_keys.add( k )
    for key in all_keys:
        yield key, sum( d.get(key,0) for d in dict_list)

def f3(list_dictionaries):
    return dict(union( list_dictionaries ))

Вот результаты:

% python -mtimeit -s"import test" "test.f1(test.list_dictionaries)"
1000 loops, best of 3: 776 usec per loop
% python -mtimeit -s"import test" "test.f2(test.list_dictionaries)"
1000 loops, best of 3: 432 usec per loop    
% python -mtimeit -s"import test" "test.f3(test.list_dictionaries)"
100 loops, best of 3: 2.19 msec per loop
9
ответ дан 6 December 2019 в 22:59
поделиться

Используйте вместо него collections.defaultdict .

http://docs.python.org/library/collections.html#defaultdict-objects

Немного проще.

1
ответ дан 6 December 2019 в 22:59
поделиться

Вы могли бы почерпнуть вдохновение из карты Google-reduce. Насколько я понимаю, он был разработан для решения именно такого типа проблем.

0
ответ дан 6 December 2019 в 22:59
поделиться

Это тоже может быть быстро, но это действительно зависит от ваших данных. Это позволяет избежать всех изменяющихся диктовок или дополнительных списков - только один набор всех ключей и множество чтений: -)

from itertools import chain

def union( dict_list ):
    all_keys = set(chain.from_iterable(dict_list))
    for key in all_keys:
        yield key, sum( d.get(key,0) for d in dict_list)

combined = dict(union( dict_list ))
1
ответ дан 6 December 2019 в 22:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: