Как суммировать элементы в списке словарей, если два ключевых значения одинаковы
У меня есть следующий список словарей:
dictionary =[{'Flow': 100, 'Location': 'USA', 'Name': 'A1'},
{'Flow': 90, 'Location': 'Europe', 'Name': 'B1'},
{'Flow': 20, 'Location': 'USA', 'Name': 'A1'},
{'Flow': 70, 'Location': 'Europe', 'Name': 'B1'}]
Я хочу создать новый список словарей с суммированными значениями Flow
для всех словарей, где Location
and Name
одинаковы. Мой желаемый результат:
new_dictionary =[{'Flow': 120, 'Location': 'USA', 'Name': 'A1'},
{'Flow': 160, 'Location': 'Europe', 'Name': 'B1'},]
Как я могу это достичь?
Ответы
Ответ 1
Это возможно, но нетривиально для реализации в python. Могу я предложить использовать панды? Это просто с groupby
, sum
и to_dict
.
import pandas as pd
(pd.DataFrame(dictionary)
.groupby(['Location', 'Name'], as_index=False)
.Flow.sum()
.to_dict('r'))
[{'Flow': 160, 'Location': 'Europe', 'Name': 'B1'},
{'Flow': 120, 'Location': 'USA', 'Name': 'A1'}]
Чтобы установить, используйте pip install --user pandas
.
В противном случае вы можете применить псевдо-общую операцию группы, используя itertools.groupby
.
from itertools import groupby
from operator import itemgetter
grouper = ['Location', 'Name']
key = itemgetter(*grouper)
dictionary.sort(key=key)
[{**dict(zip(grouper, k)), 'Flow': sum(map(itemgetter('Flow'), g))}
for k, g in groupby(dictionary, key=key)]
[{'Flow': 160, 'Location': 'Europe', 'Name': 'B1'},
{'Flow': 120, 'Location': 'USA', 'Name': 'A1'}]
Ответ 2
Хотя я также предпочел бы использовать Pandas, если это возможно, вот решение, использующее простой python:
In [1]: import itertools
In [2]: dictionary =[{'Flow': 100, 'Location': 'USA', 'Name': 'A1'},
...: {'Flow': 90, 'Location': 'Europe', 'Name': 'B1'},
...: {'Flow': 20, 'Location': 'USA', 'Name': 'A1'},
...: {'Flow': 70, 'Location': 'Europe', 'Name': 'B1'}]
...:
In [3]: import operator
In [4]: key = operator.itemgetter('Location', 'Name')
In [5]: [{'Flow': sum(x['Flow'] for x in g),
...: 'Location': k[0],
...: 'Name': k[1]}
...: for k, g in itertools.groupby(sorted(dictionary, key=key), key=key)]
...:
...:
Out[5]:
[{'Flow': 160, 'Location': 'Europe', 'Name': 'B1'},
{'Flow': 120, 'Location': 'USA', 'Name': 'A1'}]
Другой способ - использовать defaultdict, который дает вам немного другое представление (хотя вы можете преобразовать его обратно в список dicts, если хотите):
In [11]: import collections
In [12]: cnt = collections.defaultdict(int)
In [13]: for r in dictionary:
...: cnt[(r['Location'], r['Name'])] += r['Flow']
...:
In [14]: cnt
Out[14]: defaultdict(int, {('Europe', 'B1'): 160, ('USA', 'A1'): 120})
In [15]: [{'Flow': x, 'Location': k[0], 'Name': k[1]} for k, x in cnt.items()]
Out[15]:
[{'Flow': 120, 'Location': 'USA', 'Name': 'A1'},
{'Flow': 160, 'Location': 'Europe', 'Name': 'B1'}]
Ответ 3
Не точно результат, который вы ожидаете, но..
Использование collections.Counter()
count = Counter()
for i in dictionary:
count[i['Location'], i['Name']] += i['Flow']
print count
Дам:
Counter({ ('Europe', 'B1'): 160,
('USA', 'A1'): 120 })
Надеюсь, это по крайней мере даст вам некоторую идею.