【问题标题】:Merge a list of dicts into a single dict adding values for common keys将字典列表合并到单个字典中,为公共键添加值
【发布时间】:2020-08-05 09:28:01
【问题描述】:

我怎样才能打开这样的字典列表

dico = [{'a':1}, {'b':2}, {'c':1}, {'d':2}, {'e':2}, {'d':3}, {'g':1}, {'h':4}, {'h':2}, {'f':6}, {'a':2}, {'b':2}]

像这样进入单个字典

{'a':3, 'b':4, 'c':1, 'd':5,'e':2,'f':6 , 'g':1 ,'h':6}

此时此刻

result = {}
for d in dico:
  result.update(d)
print(result)

结果:

{'a': 2, 'b': 2, 'c': 1, 'd': 3, 'e': 2, 'g': 1, 'h': 2, 'f': 6}

【问题讨论】:

    标签: python list dictionary merge


    【解决方案1】:

    只需将您的字典替换为 collections.Counter 即可:

    from collections import Counter
    
    dico = [{'a':1}, {'b':2}, {'c':1}, {'d':2}, {'e':2}, {'d':3}, {'g':1}, {'h':4}, {'h':2}, {'f':6}, {'a':2}, {'b':2}]
    
    result = Counter()
    for d in dico:
        result.update(d)
    print(result)
    

    输出:

    Counter({'h': 6, 'f': 6, 'd': 5, 'b': 4, 'a': 3, 'e': 2, 'c': 1, 'g': 1})
    

    为什么上述内容适用于 updateCounter 来自 docs

    元素是从另一个映射(或计数器)的可迭代或附加元素中计算出来的。像 dict.update() 一样,但添加计数而不是替换它们。此外,iterable 应该是一个元素序列,而不是(键,值)对的序列。

    【讨论】:

      【解决方案2】:

      这是一种使用collections.Counter 的奇特方法,它是一种字典:

      from collections import Counter
      
      def add_dicts(dicts):
          return sum(map(Counter, dicts), Counter())
      

      上述方法对于大量字典来说效率不高,因为它为结果创建了许多中间Counter 对象,而不是就地更新一个结果,因此它以二次时间运行。这是一个在线性时间内运行的类似解决方案:

      from collections import Counter
      
      def add_dicts(dicts):
          out = Counter()
          for d in dicts:
              out += d
          return out
      

      【讨论】:

        【解决方案3】:

        使用defaultdict

        from collections import defaultdict
        dct = defaultdict(int)
        
        for element in dico:
            for key, value in element.items():
                dct[key] += value
        
        print(dct)
        

        产量

        defaultdict(<class 'int'>, 
            {'a': 3, 'b': 4, 'c': 1, 'd': 5, 'e': 2, 'g': 1, 'h': 6, 'f': 6})
        


        至于时间测量,这是四个答案之间的比较:
        from collections import defaultdict, Counter
        from timeit import timeit
        
        def solution_dani():
            result = sum((Counter(e) for e in dico), Counter())
        
        def solution_kaya():
            return sum(map(Counter, dico), Counter())
        
        def solution_roadrunner():
            result = Counter()
            for d in dico:
                result.update(d)
            return result
        
        def solution_jan():
            dct = defaultdict(int)
            for element in dico:
                for key, value in element.items():
                    dct[key] += value
            return dct
        
        print(timeit(solution_dani, number=10000))
        print(timeit(solution_kaya, number=10000))
        print(timeit(solution_roadrunner, number=10000))
        print(timeit(solution_jan, number=10000))
        

        在我的MacBookAir 上产生

        0.839742998
        0.8093687279999999
        0.18643740100000006
        0.04764247300000002
        

        因此,使用默认 dict 的解决方案到目前为止是最快的(因子 15-20),其次是 @RoadRunner。

        【讨论】:

          【解决方案4】:

          使用collections.Countersum

          from collections import Counter
          
          dico = [{'a':1}, {'b':2}, {'c':1}, {'d':2}, {'e':2}, {'d':3}, {'g':1}, {'h':4}, {'h':2}, {'f':6}, {'a':2}, {'b':2}]
          
          
          result = sum((Counter(e) for e in dico), Counter())
          print(result)
          

          输出

          Counter({'h': 6, 'f': 6, 'd': 5, 'b': 4, 'a': 3, 'e': 2, 'c': 1, 'g': 1})
          

          如果您需要一本严格的字典,请执行以下操作:

          result = dict(sum((Counter(e) for e in dico), Counter()))
          print(result)
          

          你可以修改你的方法,像这样:

          result = {}
          for d in dico:
              for key, value in d.items():
                  result[key] = result.get(key, 0) + value
          
          print(result)
          

          update 方法将替换文档中现有键的值:

          用其他的键/值对更新字典,覆盖 现有的密钥。

          【讨论】:

            【解决方案5】:
            import collections
            
            counter = collections.Counter()
            
            for d in dico:
                counter.update(d)
            
            result = dict(counter)
            print(result)
            

            输出

            {'a': 3, 'b': 4, 'c': 1, 'd': 5, 'e': 2, 'g': 1, 'h': 6, 'f': 6}
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2023-01-26
              • 2020-04-24
              • 1970-01-01
              • 2022-07-06
              • 2011-03-30
              • 2017-12-12
              • 1970-01-01
              相关资源
              最近更新 更多