Ответ 1
Немного уродливый, но однострочный:
dictf = reduce(lambda x, y: dict((k, v + y[k]) for k, v in x.iteritems()), dict1)
В Python, У меня есть список dicts:
dict1 = [{'a':2, 'b':3},{'a':3, 'b':4}]
Мне нужен один последний дикт, который будет содержать сумму всех dicts.
I.e результат будет: {'a':5, 'b':7}
N.B: каждый dict в списке будет содержать одинаковое количество пар ключей, значений.
Немного уродливый, но однострочный:
dictf = reduce(lambda x, y: dict((k, v + y[k]) for k, v in x.iteritems()), dict1)
Вы можете использовать collections.Counter
counter = collections.Counter()
for d in dict1:
counter.update(d)
Или, если вы предпочитаете oneliners:
functools.reduce(operator.add, map(collections.Counter, dict1))
Усиление sum()
должно повысить производительность при добавлении более чем нескольких dicts
>>> dict1 = [{'a':2, 'b':3},{'a':3, 'b':4}]
>>> from operator import itemgetter
>>> {k:sum(map(itemgetter(k), dict1)) for k in dict1[0]} # Python2.7+
{'a': 5, 'b': 7}
>>> dict((k,sum(map(itemgetter(k), dict1))) for k in dict1[0]) # Python2.6
{'a': 5, 'b': 7}
добавление предложения Стефана
>>> {k: sum(d[k] for d in dict1) for k in dict1[0]} # Python2.7+
{'a': 5, 'b': 7}
>>> dict((k, sum(d[k] for d in dict1)) for k in dict1[0]) # Python2.6
{'a': 5, 'b': 7}
Я думаю, что версия Stephan кода Python2.7 читается действительно красиво
Это может помочь:
def sum_dict(d1, d2):
for key, value in d1.items():
d1[key] = value + d2.get(key, 0)
return d1
>>> dict1 = [{'a':2, 'b':3},{'a':3, 'b':4}]
>>> reduce(sum_dict, dict1)
{'a': 5, 'b': 7}
В следующем коде показан один из способов:
dict1 = [{'a':2, 'b':3},{'a':3, 'b':4}]
final = {}
for k in dict1[0].keys(): # Init all elements to zero.
final[k] = 0
for d in dict1:
for k in d.keys():
final[k] = final[k] + d[k] # Update the element.
print final
Выводится:
{'a': 5, 'b': 7}
по вашему желанию.
Или, как вдохновлено крисом, лучше, но все еще читаемо:
dict1 = [{'a':2, 'b':3},{'a':3, 'b':4}]
final = {}
for d in dict1:
for k in d.keys():
final[k] = final.get(k,0) + d[k]
print final
Я сосну для дней оригинального, читаемого Python: -)
Меня интересовала производительность предлагаемых методов Counter, сокращения и суммирования для больших списков. Возможно, кому-то это тоже интересно. Вы можете посмотреть здесь: https://gist.github.com/torstenrudolf/277e98df296f23ff921c
Я проверил три метода для этого списка словарей:
dictList = [{'a': x, 'b': 2*x, 'c': x**2} for x in xrange(10000)]
метод суммирования показал лучшую производительность, за которой следует сокращение, а счетчик был самым медленным. Время, показанное ниже, находится в секундах.
In [34]: test(dictList)
Out[34]:
{'counter': 0.01955194902420044,
'reduce': 0.006518083095550537,
'sum': 0.0018319153785705566}
Но это зависит от количества элементов в словарях. метод sum будет замедляться быстрее, чем сокращение.
l = [{y: x*y for y in xrange(100)} for x in xrange(10000)]
In [37]: test(l, num=100)
Out[37]:
{'counter': 0.2401433277130127,
'reduce': 0.11110662937164306,
'sum': 0.2256883692741394}
Вот разумный, красивый.
final = {}
for k in dict1[0].Keys():
final[k] = sum(x[k] for x in dict1)
return final
В Python 2.7 вы можете заменить dict с помощью collections.Counter объекта. Это поддерживает сложение и вычитание счетчиков.
Вот еще одно рабочее решение (python3), довольно общее, поскольку оно работает для dict, списков, массивов. Для необычных элементов исходное значение будет включено в выходной текст.
def mergsum(a, b):
for k in b:
if k in a:
b[k] = b[k] + a[k]
c = {**a, **b}
return c
dict1 = [{'a':2, 'b':3},{'a':3, 'b':4}]
print(mergsum(dict1[0], dict1[1]))
Еще одно однострочное решение
dict(
functools.reduce(
lambda x, y: x.update(y) or x, # update, returns None, and we need to chain.
dict1,
collections.Counter())
)
Это создает только один счетчик, использует его в качестве аккумулятора и, наконец, преобразует обратно в dict.