【问题标题】:Unpack list of dictionaries in Python在 Python 中解压字典列表
【发布时间】:2020-03-15 08:23:26
【问题描述】:

问题

根据this answer,在Python 3.5或更高版本中,可以通过解包合并两个字典xy

z = {**x, **y}

是否可以解压一个可变的字典列表?类似的东西

def merge(*dicts):
    return {***dicts} # this fails, of course. What should I use here?

例如,我希望

list_of_dicts = [{'a': 1, 'b': 2}, {'c': 3}, {'d': 4}]
{***list_of_dicts} == {'a': 1, 'b': 2, 'c': 3, 'd': 4}

请注意,这个问题不是关于如何合并字典列表,因为上面的链接提供了答案。这里的问题是:是否有可能以及如何解压字典列表?

编辑

正如 cmets 中所述,这个问题与this one 非常相似。但是,解压缩字典列表不同于简单地合并它们。假设有一个运算符*** 旨在解包字典列表,并给出

def print_values(a, b, c, d):
    print('a =', a)
    print('b =', b)
    print('c =', c)
    print('d =', d)

list_of_dicts = [{'a': 1, 'b': 2}, {'c': 3}, {'d': 4}]

可以写

print_values(***list_of_dicts)

而不是

print_values(**merge(list_of_dicts))

【问题讨论】:

  • 不,没有使用语法糖的本地方法。
  • @TheIncorrigible1,我认为您的评论是对这个问题的最准确答案。谢谢。
  • 相关,甚至可能是重复的,因为这个问题的答案只是“否”:How do I merge a list of dicts into a single dict?
  • @Georgy,感谢您指出这一点。事实上,{k: v for d in L for k, v in d.items()} 的解决方案看起来非常好。但是,我不确定这是否是重复的,因为我正在寻找用于解压缩字典列表的语法糖,而该问题涉及合并。
  • @Georgy,我编辑了这个问题,旨在展示除合并之外的另一个解包应用程序。希望它能阐明我的问题与您分享的问题之间的区别。

标签: python python-3.x dictionary merge


【解决方案1】:

另一种解决方案是使用collections.ChainMap

from collections import ChainMap

dict(ChainMap(*list_of_dicts[::-1]))

Out[88]: {'a': 1, 'b': 2, 'c': 3, 'd': 4}

【讨论】:

  • ChainMap 比合并更好:它避免了创建新的字典。此外,可以将 ChainMap 视为字典列表(通过 ChainMap.maps)或合并字典(如您在答案中所示)。此外,它提供了更大的灵活性,并使用标准包而不是自行实现的功能。很好,谢谢!
  • 另外,它支持这两种类型的解包。定义cm = ChainMap(*list_of_dicts[::-1]),可以使用列表解包,如*cm.maps,也可以使用字典解包,如**cm
  • 来这里看看为什么我的回答不被接受;这好多了。我想我以前从未注意到ChainMap
【解决方案2】:

您可以遍历列表并使用update

lst = [{'a': 1, 'b': 2}, {'c': 3}, {'d': 4}]

dct = {}
for item in lst:
    dct.update(item)

print(dct)
# {'a': 1, 'b': 2, 'c': 3, 'd': 4}

【讨论】:

  • 谢谢,这似乎非常适合合并dicts。实际上,这是this post中提供的答案。但是,这更侧重于合并而不是解包的使用,这是我首先关心的问题,如问题中所述。
【解决方案3】:

对此没有语法,但您可以使用itertools.chain 将每个字典中的键/值元组连接到dict 可以使用的单个流中。

from itertools import chain


def merge(*dicts):
    return dict(chain.from_iterable(d.items() for d in dicts))

您也可以解压由列表推导式创建的列表:

def merge(*dicts):
    return dict(*[d.items() for d in dicts])

【讨论】:

  • merge 的第二个实现最接近我的要求,谢谢!
【解决方案4】:

要合并多个字典,可以使用函数reduce

from functools import reduce

lst = [{'a': 1, 'b': 2}, {'c': 3}, {'d': 4}]

reduce(lambda x, y: dict(**x, **y), lst)
# {'a': 1, 'b': 2, 'c': 3, 'd': 4}

【讨论】:

  • 这个确实不错。只是好奇(这在我的问题中并不重要),关于性能,这个实现是否比其他实现更快?
  • @rugortal 我不这么认为。在此解决方案中,您为每个子字典构建一个新字典,而在另一个使用 update 的解决方案中,您有一个字典并更新它。
【解决方案5】:

您可以使用列表推导并将这个可迭代对象作为 dict 的参数

def merge(*dicts):
    lst = [*[d.items() for d in dicts]]
    return dict(lst)

【讨论】:

  • 感谢您的回答。这与我正在寻找的非常接近。不过,我会坚持选择的答案有两个原因:它之前发布过,并且该版本不会创建中间 lst
  • 你能发布整个代码吗,因为我无法让它工作。
【解决方案6】:

您可以只使用列表推导来遍历列表中的所有字典,然后遍历每个字典的项目,最后将它们转换为字典

>>> lst = [{'a':1}, {'b':2}, {'c':1}, {'d':2}]
>>> dict(kv for d in lst for kv in d.items())
{'a': 1, 'b': 2, 'c': 1, 'd': 2}

【讨论】:

    【解决方案7】:

    您可以使用reduce 一次合并两个字典,使用dict.update

    >>> from functools import reduce
    >>> lst = [{'a':1}, {'b':2}, {'c':1}, {'d':2}]
    >>> reduce(lambda d1, d2: d1.update(d2) or d1, lst, {})
    {'a': 1, 'b': 2, 'c': 1, 'd': 2}
    
    

    【讨论】:

      【解决方案8】:

      当您 *dicts 将其作为元组放入时,您可以使用 d[0] 将列表拉出,然后将这种理解用于非统一键

      list_of_dicts = [{'a': 1, 'b': 2}, {'c': 3}, {'d': 4}]
      
      def merge(*dicts):    
          return dict( j for i in dicts[0] for j in i.items())
      
      print(merge(list_of_dicts)) 
      
      {'a': 1, 'b': 2, 'c': 3, 'd': 4}
      [Program finished]
      

      【讨论】:

        猜你喜欢
        • 2020-07-21
        • 2011-11-01
        • 1970-01-01
        • 2011-03-14
        • 1970-01-01
        • 2016-12-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多