繁体   English   中英

字典在字典理解中合并

[英]Dict merge in a dict comprehension

在 python 3.5 中,我们可以使用 double-splat 解包合并字典

>>> 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, {}) ,这看起来更难看。 为什么在该表达式中似乎没有任何歧义时,解析器不允许使用“一种明显的方法”?

这不完全是您问题的答案,但我认为使用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指出)“首次发现使用”等等,这取决于你的意图,你可能需要对呼叫reversed通过你的前dict s转换ChainMap

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

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

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

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

这很快并且可能非常高效。 我不知道我可以为 python 开发人员说话,但我不知道你期望的版本更容易阅读。 例如,由于缺少: ,您的理解对我来说更像是集合理解。 FWIW,我不认为有任何技术原因(例如解析器歧义)他们不能添加这种形式的理解解包。

显然,这些形式是被提议的,但没有得到足够普遍的支持来保证实施它们(还)。

final = {}
for data in [d1, d2]:
    final = {**final,**data}

您可以使用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}

你可以定义这个函数:

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'}

基于此解决方案,@ilgia-everilä 也提到过,但使其与 Py2 兼容并仍然避免中间结构。 将它封装在一个函数中使得它的使用非常易读。

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)

惯用语,没有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'}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM