如果两个键的值相同,如何对包含字典的列表中的元素求和

15

我有以下字典列表:

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值相加的结果,且这些字典的LocationName都相同。我的期望输出如下所示:

new_dictionary =[{'Flow': 120, 'Location': 'USA', 'Name': 'A1'},
            {'Flow': 160, 'Location': 'Europe', 'Name': 'B1'},]

我该如何实现这个目标?

3个回答

17

这是可能的,但在Python中实现起来并不容易。我可以建议使用pandas吗?使用groupbysumto_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'}]

1
我想要对答案下投反对票,因为底部一行代码难以阅读,但是答案的上半部分看起来完全没问题。我该怎么办? :( (附注:您可以将**{'Flow': sum(map(itemgetter('Flow'), g))}简化为'Flow': sum(map(itemgetter('Flow'), g)) - Aran-Fey
你如何在没有任何库的情况下解决它?(没有pandas,没有itertools)@Aran-Fey - emily.mi
1
@emily.mi 我不会这样做。 - Aran-Fey

10

虽然如果可能的话我也更喜欢使用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,它会给你一个稍微不同的表示(虽然如果你想的话,可以将其转换回字典列表):

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'}]

你如何在没有任何库的情况下解决它?(没有pandas,没有itertools)@awesoon - emily.mi
你可以在这里阅读更多关于defaultdict的内容:https://docs.python.org/3/library/collections.html#collections.defaultdict,它可能会给你一些提示,如何用普通的`dict`替换它。 - awesoon

6
不完全符合您的预期输出,但是...
使用collections.Counter()
count = Counter()

for i in dictionary:
    count[i['Location'], i['Name']] += i['Flow']

print count

将会提供:

Counter({ ('Europe', 'B1'): 160, 
          ('USA', 'A1'): 120 })

我希望这至少能给你一些想法。

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