【问题标题】:How do I merge a list of dicts into a single dict?如何将字典列表合并到单个字典中?
【发布时间】:2011-03-30 12:33:48
【问题描述】:

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

[{'a':1}, {'b':2}, {'c':1}, {'d':2}]

...变成这样的单个字典:

{'a':1, 'b':2, 'c':1, 'd':2}

【问题讨论】:

  • 是的,虽然它合并到一个列表的字典中。
  • 这是一个列表而不是一个字典:>>> type([{'a':1},{'b':2}])
  • 考虑到它出现的频率,真的应该有一个衬里。是否有不支持 {**d for d in d_list} 的原因?

标签: python list dictionary


【解决方案1】:

这适用于任何长度的字典:

>>> result = {}
>>> for d in L:
...    result.update(d)
... 
>>> result
{'a':1,'c':1,'b':2,'d':2}

作为comprehension

# Python >= 2.7
{k: v for d in L for k, v in d.items()}

# Python < 2.7
dict(pair for d in L for pair in d.items())

【讨论】:

    【解决方案2】:

    对于 Python 3.3+,有一个 ChainMap collection:

    >>> from collections import ChainMap
    >>> a = [{'a':1},{'b':2},{'c':1},{'d':2}]
    >>> dict(ChainMap(*a))
    {'b': 2, 'c': 1, 'a': 1, 'd': 2}
    

    另见:

    【讨论】:

    • 比第一个 dict 理解解决方案慢 10 倍
    【解决方案3】:

    这类似于@delnan,但提供了修改 k/v(键/值)项的选项,我相信它更具可读性:

    new_dict = {k:v for list_item in list_of_dicts for (k,v) in list_item.items()}
    

    例如,替换 k/v 元素如下:

    new_dict = {str(k).replace(" ","_"):v for list_item in list_of_dicts for (k,v) in list_item.items()}
    

    在将 dict 对象拉出列表后,从字典 .items() 生成器中解压缩 k,v 元组

    【讨论】:

      【解决方案4】:

      PEP 448 解包字典对@dietbuddha 答案的小改进,对我来说,这种方式更具可读性,也是faster as well

      from functools import reduce
      result_dict = reduce(lambda a, b: {**a, **b}, list_of_dicts)
      

      但请记住,这仅适用于 Python 3.5+ 版本。

      【讨论】:

        【解决方案5】:

        对于平面词典,您可以这样做:

        from functools import reduce
        reduce(lambda a, b: dict(a, **b), list_of_dicts)
        

        【讨论】:

          【解决方案6】:
          >>> L=[{'a': 1}, {'b': 2}, {'c': 1}, {'d': 2}]    
          >>> dict(i.items()[0] for i in L)
          {'a': 1, 'c': 1, 'b': 2, 'd': 2}
          

          注意:'b' 和 'c' 的顺序与您的输出不匹配,因为 dicts 是无序的

          如果字典可以有多个键/值

          >>> dict(j for i in L for j in i.items())
          

          【讨论】:

          • 如果列表中的任何 dicts 包含多个项目,则失败。
          • 咳*(假设每个字典只包含一个键值对)*咳
          • 啊,首先我发布了一个适用于一般 dicts 的方法,但看起来 OP 不需要它
          【解决方案7】:
          dict1.update( dict2 )
          

          这是不对称的,因为您需要选择如何处理重复的密钥;在这种情况下,dict2 将覆盖dict1。换一种方式。

          编辑:啊,抱歉,没看到。

          可以在一个表达式中做到这一点:

          >>> from itertools import chain
          >>> dict( chain( *map( dict.items, theDicts ) ) )
          {'a': 1, 'c': 1, 'b': 2, 'd': 2}
          

          最后这件事不归功于我!

          但是,我认为使用简单的 for 循环执行此操作可能更符合 Python 风格(显式 > 隐式、平面 > 嵌套)。 YMMV。

          【讨论】:

          • 它是一个列表而不是一个字典:>>> type([{'a':1},{'b':2}])
          【解决方案8】:

          您可以使用funcy 库中的join 函数:

          from funcy import join
          join(list_of_dicts)
          

          【讨论】:

          • 我认为这是一个被低估的答案...
          【解决方案9】:

          如果您不再需要单例字典:

          >>> L = [{'a':1}, {'b':2}, {'c':1}, {'d':2}]
          >>> dict(map(dict.popitem, L))
          {'a': 1, 'b': 2, 'c': 1, 'd': 2}
          

          【讨论】:

            【解决方案10】:
            >>> dictlist = [{'a':1},{'b':2},{'c':1},{'d':2, 'e':3}]
            >>> dict(kv for d in dictlist for kv in d.iteritems())
            {'a': 1, 'c': 1, 'b': 2, 'e': 3, 'd': 2}
            >>>
            

            请注意,我在最后一个字典中添加了第二个键/值对,以表明它适用于多个条目。 列表中后面的 dicts 中的键也将覆盖早期 dict 中的相同键。

            【讨论】:

              猜你喜欢
              • 2019-03-12
              • 2017-04-11
              • 2017-11-27
              • 1970-01-01
              • 2021-04-10
              • 2020-08-05
              • 1970-01-01
              相关资源
              最近更新 更多