【问题标题】:How to sum dict elements如何对dict元素求和
【发布时间】:2011-03-30 06:39:32
【问题描述】:

在 Python 中, 我有字典列表:

dict1 = [{'a':2, 'b':3},{'a':3, 'b':4}]

我想要一个包含所有字典总和的最终字典。 即结果将是:{'a':5, 'b':7}

注意:列表中的每个 dict 都将包含相同数量的键值对。

【问题讨论】:

    标签: python dictionary sum


    【解决方案1】:

    您可以使用collections.Counter

    counter = collections.Counter()
    for d in dict1: 
        counter.update(d)
    

    或者,如果您更喜欢单线:

    functools.reduce(operator.add, map(collections.Counter, dict1))
    

    【讨论】:

    • sum(map(collections.Counter, dict1),Counter())。但我不确定创建所有这些的功能版本的相对性能Counters()
    • 这个答案展示了 Python 编程的黄金法则:如果它包含在 Python 中,请不要重新发明轮子。一点:最终结果counterdict 子类的一个实例,如果OP 想要一个普通的dict,他可能会添加一个最终的counter = dict(counter)
    • 如果 dicts 不具有相同的键,第一个解决方案将仅输出所有 dicts 之间共享的键的结果,而第二个单线解决方案将输出所有键的结果 (将缺失的键视为值 0)
    【解决方案2】:

    有点难看,但单线:

    dictf = reduce(lambda x, y: dict((k, v + y[k]) for k, v in x.iteritems()), dict1)
    

    【讨论】:

    • 其实我有一个对象列表,这个字典是一个对象属性,有什么解决办法吗? :(
    • [ob1, ob2, ob3].. 每个对象都有一个属性 data ob1.data 它返回一个 dict {'a':2, 'b':3} 这样
    • dictf = reduce(lambda x, y: dict((k, v + y.data[k]) for k, v in x.data.iteritems()), dict1
    • 我的代码使用这个解决方案..ok...reduce(lambda x, y: dict((k, v + y.get_local_expenses()[k] if not isinstance(y.get_local_expenses( )[k], dict) else 0) for k, v in x.get_local_expenses().iteritems()), glc)
    • @nazmul hasan:6 个月后你会明白吗?您已经写了 3 次 get_local_expenses() —— 有必要吗?什么是glc?你读过@paxdiablo 的回答吗?
    【解决方案3】:

    在添加多个字典时,利用 sum() 应该会获得更好的性能

    >>> 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 代码读起来非常好

    【讨论】:

    • 你有什么理由在内部循环中使用mapitemgetter 而不是列表解析(即dict((k, sum(d[k] for d in dict1)) for k in dict1[0]))?
    • @stephan,它曾经更快..现在似乎是差不多的速度。我会把它添加到我的答案中
    • 谢谢,我不知道。 +1
    • 这个版本的一个很好的补充,它还检查 dict 类型以确保我们可以在它们之上进行数学运算:{k: sum(d[k] if type(d[k]) in (int, float) else 0 for d in dict1) for k in dict1[0]}
    【解决方案4】:

    这可能会有所帮助:

    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}
    

    【讨论】:

      【解决方案5】:

      以下代码显示了一种方法:

      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}
      

      如你所愿。

      或者,受 Kriss 的启发,更好但仍然可读:

      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 时代:-)

      【讨论】:

      • 您可以将第一个for 循环简化为final={}.fromkeys(dict1[0],0)。或者这就是“可读”的意思? :)
      • 我可以将整个事情简化为卡尔的答案,但这意味着(1)我不妨删除我的答案; (2) 下个月我发现我需要做一点小改动时将无法阅读它 :-) 我应该提到我使用 Python 进行教学(my 品牌的 Python 而不是 carl 的品牌)。它确实是一种向孩子们教授基础知识(序列、迭代、选择)的好语言,但是,如果你要用 lambdas 之类的东西让他们头疼,你不妨教他们 F# 或 Haskell。
      • @paxdiablo:为了可读性,您可以完全删除init循环,只需将+ d[k]替换为+ res.get(k, 0)
      • 这很好,@kriss,并且仍然非常易读,但我认为您的意思是用 final.get(k,0) + d[k] 替换 final[k] + d[k] - 这是我需要的 final 字典,如果密钥不存在 - 我知道它适用于 d
      • @paxdiablo:哎呀!是的,你完全正确,我倒了字典。
      【解决方案6】:

      我对针对大型列表提出的 Counter、reduce 和 sum 方法的性能感兴趣。也许其他人也对此感兴趣。 你可以看这里:https://gist.github.com/torstenrudolf/277e98df296f23ff921c

      我为这个字典列表测试了三种方法:

      dictList = [{'a': x, 'b': 2*x, 'c': x**2} for x in xrange(10000)]
      

      sum 方法的性能最好,reduce 次之,Counter 最慢。下面显示的时间以秒为单位。

      In [34]: test(dictList)
      Out[34]: 
      {'counter': 0.01955194902420044,
       'reduce': 0.006518083095550537,
       'sum': 0.0018319153785705566}
      

      但这取决于字典中元素的数量。 sum 方法会比 reduce 方法减速得更快。

      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}
      

      【讨论】:

        【解决方案7】:

        在 Python 2.7 中,您可以将 dict 替换为 collections.Counter 对象。这支持计数器的加法和减法。

        【讨论】:

          【解决方案8】:

          这是一个合理的美丽。

          final = {}
          for k in dict1[0].Keys():
              final[k] = sum(x[k] for x in dict1)
          return final
          

          【讨论】:

            【解决方案9】:

            您还可以使用 pandas sum 函数来计算总和:

            import pandas as pd
            # create a DataFrame
            df = pd.DataFrame(dict1)
            # compute the sum and convert to dict.
            dict(df.sum())
            

            这会导致:

            {'a': 5, 'b': 7}
            

            它也适用于浮点数:

            dict2 = [{'a':2, 'b':3.3},{'a':3, 'b':4.5}]
            dict(pd.DataFrame(dict2).sum())
            

            给出正确的结果:

            {'a': 5.0, 'b': 7.8}
            

            【讨论】:

              【解决方案10】:

              这是另一个可行的解决方案(python3),非常通用,因为它适用于字典、列表、数组。对于不常见的元素,原始值将包含在输出字典中。

              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]))
              

              【讨论】:

                【解决方案11】:

                另一种单线解决方案

                dict(
                    functools.reduce(
                        lambda x, y: x.update(y) or x,  # update, returns None, and we need to chain.
                        dict1,
                        collections.Counter())
                )
                

                这只会创建一个计数器,将其用作累加器并最终转换回字典。

                【讨论】:

                  猜你喜欢
                  • 2014-12-15
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-01-29
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-09-01
                  相关资源
                  最近更新 更多