python 字典理解中的字典合并

fdx2calv  于 2023-02-15  发布在  Python
关注(0)|答案(6)|浏览(111)

在python3.5中,我们可以使用double-splat解包来合并dicts

>>> d1 = {1: 'one', 2: 'two'}
>>> d2 = {3: 'three'}
>>> {**d1, **d2}
{1: 'one', 2: 'two', 3: 'three'}

酷。不过,它似乎并不适用于动态用例:

>>> ds = [d1, d2]
>>> {**d for d in ds}
SyntaxError: dict unpacking cannot be used in dict comprehension

相反,我们必须执行reduce(lambda x,y: {**x, **y}, ds, {}),这看起来要丑陋得多。为什么解析器不允许“一种明显的方法”,而表达式中似乎没有任何歧义?

baubqpgj

baubqpgj1#

这并不能完全回答您的问题,但我认为使用ChainMap是一种惯用且优雅的方式来完成您的建议(内联合并字典):

>>> from collections import ChainMap
>>> d1 = {1: 'one', 2: 'two'}
>>> d2 = {3: 'three'}
>>> ds = [d1, d2]
>>> dict(ChainMap(*ds))
{1: 'one', 2: 'two', 3: 'three'}

虽然这不是一个特别透明的解决方案,因为许多程序员可能不知道ChainMap是如何工作的,注意(正如@AnttiHaapala指出的)“首先找到的是使用的”,所以根据您的意图,您可能需要在将dict传递到ChainMap之前调用reversed

>>> d2 = {3: 'three', 2: 'LOL'}
>>> ds = [d1, d2]
>>> dict(ChainMap(*ds))
{1: 'one', 2: 'two', 3: 'three'}

>>> dict(ChainMap(*reversed(ds)))
{1: 'one', 2: 'LOL', 3: 'three'}
hfwmuf9z

hfwmuf9z2#

对我来说,显而易见的方式是:

d_out = {}
for d in ds:
    d_out.update(d)

这是快速的,而且可能是相当高性能的。我不知道我能不能代表python开发人员,但是我不知道你期望的版本是否更容易阅读。例如,你的理解在我看来更像是一个集合理解,因为缺少:.FWIW。我不认为有任何 * 技术 * 原因(例如解析器歧义),他们 * 不能 * 添加这种形式的理解解包。
显然,这些形式被提出,但没有得到足够的普遍支持,以保证实施它们(尚未)。

yws3nbqq

yws3nbqq3#

您可以使用itertools.chainitertools.chain.from_iterable

import itertools

ds = [{'a': 1, 'b': 2}, {'c': 30, 'b': 40}]

merged_d = dict(itertools.chain(*(d.items() for d in ds)))
print(merged_d)  # {'a': 1, 'b': 40, 'c': 30}
uttx8gqw

uttx8gqw4#

基于这个解决方案,@ilgia-everilä也提到过,但是使它兼容Py 2并仍然避免中间结构。将它封装在函数中使它的使用非常可读。

def merge_dicts(*dicts, **extra):
    """
    >>> merge_dicts(dict(a=1, b=1), dict(b=2, c=2), dict(c=3, d=3), d=4, e=4)
    {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 4}
    """
    return dict((
        (k,v)
        for d in dicts
        for k,v in d.items()
    ), **extra)
kse8i1jr

kse8i1jr5#

习惯用语,* 不带 * ChainMap

>>> d1 = {1: 'one', 2: 'two'}
>>> d2 = {3: 'three'}
>>> {k: v for d in [d1, d2] for k, v in d.items()}
{1: 'one', 2: 'two', 3: 'three'}
efzxgjgh

efzxgjgh6#

您可以定义此函数:

from collections import ChainMap
def mergeDicts(l):
    return dict(ChainMap(*reversed(list(l))))

然后,您可以像这样使用它:

>>> d1 = {1: 'one', 2: 'two'}
>>> d2 = {3: 'three'}
>>> ds = [d1, d2]
>>> mergeDicts(ds)
{1: 'one', 2: 'two', 3: 'three'}

相关问题