【问题标题】:How to sum elements in list of dictionaries if two key values are the same如果两个键值相同,如何对字典列表中的元素求和
【发布时间】:2018-08-27 05:51:44
【问题描述】:

我有以下字典列表:

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

我想创建一个新的字典列表,其中包含 LocationName 相同的所有字典的 Flow 值。我想要的输出是:

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

我怎样才能做到这一点?

【问题讨论】:

    标签: python list dictionary


    【解决方案1】:

    这是可能的,但在 python 中实现并非易事。我可以建议使用熊猫吗?这很简单,只需 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'}]
    

    【讨论】:

    • 我想在答案的下半部分对不可读的单行投反对票,但答案的上半部分看起来完全没问题。我应该怎么办? :((P.S.:你可以将**{'Flow': sum(map(itemgetter('Flow'), g))}简化为'Flow': sum(map(itemgetter('Flow'), g))
    • 如果没有任何库,你将如何解决它? (没有 pandas ,没有 itertools)@Aran-Fey
    • @emily.mi 我不会。
    【解决方案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'}]
    

    【讨论】:

    • 如果没有任何库,你将如何解决它? (没有 pandas ,没有 itertools)@awesoon
    • 你可以在这里阅读更多关于defaultdict的信息:docs.python.org/3/library/…,它可能会给你一些提示如何用dict替换它
    【解决方案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 })
    

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

    【讨论】:

      猜你喜欢
      • 2014-02-26
      • 1970-01-01
      • 1970-01-01
      • 2018-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多