我想将两个词典融入一个新的词典。

x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}
z = merge(x, y)

>>> z
{'a': 1, 'b': 3, 'c': 4}

每当两个字典中都有一个关键 k 时,只应保留 y(k) 的值。


当前回答

滥用导致马太福的答案的一个单词解决方案:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (lambda f=x.copy(): (f.update(y), f)[1])()
>>> z
{'a': 1, 'c': 11, 'b': 10}

你说你想要一个表达式,所以我滥用了Lambda连接一个名字,而Tuples超越Lambda的单表达式限制。

当然,你也可以这样做,如果你不在乎复制它:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (x.update(y), x)[1]
>>> z
{'a': 1, 'b': 10, 'c': 11}

其他回答

这是 Python 3.5 或更大的表达式,将使用 Reduction 的字典组合:

>>> from functools import reduce
>>> l = [{'a': 1}, {'b': 2}, {'a': 100, 'c': 3}]
>>> reduce(lambda x, y: {**x, **y}, l, {})
{'a': 100, 'b': 2, 'c': 3}

注意:即使字典列表是空的,或者只有一个元素。

在 Python 3.9 或更高版本中,Lambda 可以直接由 operator.ior 取代:

>>> from functools import reduce
>>> from operator import ior
>>> l = [{'a': 1}, {'b': 2}, {'a': 100, 'c': 3}]
>>> reduce(ior, l, {})
{'a': 100, 'b': 2, 'c': 3}

在 Python 3.8 或更低的情况下,可以使用下列作为 ior 的替代品:

>>> from functools import reduce
>>> l = [{'a': 1}, {'b': 2}, {'a': 100, 'c': 3}]
>>> reduce(lambda x, y: x.update(y) or x, l, {})
{'a': 100, 'b': 2, 'c': 3}

2 词典

def union2(dict1, dict2):
    return dict(list(dict1.items()) + list(dict2.items()))

n 字典

def union(*dicts):
    return dict(itertools.chain.from_iterable(dct.items() for dct in dicts))

查看 https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/

深深的定律:

from typing import List, Dict
from copy import deepcopy

def merge_dicts(*from_dicts: List[Dict], no_copy: bool=False) -> Dict :
    """ no recursion deep merge of two dicts

    By default creates fresh Dict and merges all to it.

    no_copy = True, will merge all dicts to a fist one in a list without copy.
    Why? Sometime I need to combine one dictionary from "layers".
    The "layers" are not in use and dropped immediately after merging.
    """

    if no_copy:
        xerox = lambda x:x
    else:
        xerox = deepcopy

    result = xerox(from_dicts[0])

    for _from in from_dicts[1:]:
        merge_queue = [(result, _from)]
        for _to, _from in merge_queue:
            for k, v in _from.items():
                if k in _to and isinstance(_to[k], dict) and isinstance(v, dict):
                    # key collision add both are dicts.
                    # add to merging queue
                    merge_queue.append((_to[k], v))
                    continue
                _to[k] = xerox(v)

    return result

使用:

print("=============================")
print("merge all dicts to first one without copy.")
a0 = {"a":{"b":1}}
a1 = {"a":{"c":{"d":4}}}
a2 = {"a":{"c":{"f":5}, "d": 6}}
print(f"a0 id[{id(a0)}] value:{a0}")
print(f"a1 id[{id(a1)}] value:{a1}")
print(f"a2 id[{id(a2)}] value:{a2}")
r = merge_dicts(a0, a1, a2, no_copy=True)
print(f"r  id[{id(r)}] value:{r}")

print("=============================")
print("create fresh copy of all")
a0 = {"a":{"b":1}}
a1 = {"a":{"c":{"d":4}}}
a2 = {"a":{"c":{"f":5}, "d": 6}}
print(f"a0 id[{id(a0)}] value:{a0}")
print(f"a1 id[{id(a1)}] value:{a1}")
print(f"a2 id[{id(a2)}] value:{a2}")
r = merge_dicts(a0, a1, a2)
print(f"r  id[{id(r)}] value:{r}")

到目前为止,我对列出的解决方案的问题是,在合并词典中,关键“b”的值为10,但在我的思维方式上,它应该是12。

import timeit

n=100000
su = """
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
"""

def timeMerge(f,su,niter):
    print "{:4f} sec for: {:30s}".format(timeit.Timer(f,setup=su).timeit(n),f)

timeMerge("dict(x, **y)",su,n)
timeMerge("x.update(y)",su,n)
timeMerge("dict(x.items() + y.items())",su,n)
timeMerge("for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k] ",su,n)

#confirm for loop adds b entries together
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]
print "confirm b elements are added:",x

结果:

0.049465 sec for: dict(x, **y)
0.033729 sec for: x.update(y)                   
0.150380 sec for: dict(x.items() + y.items())   
0.083120 sec for: for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]

confirm b elements are added: {'a': 1, 'c': 11, 'b': 12}

可以用一个单一的理解来做到这一点:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> { key: y[key] if key in y else x[key]
      for key in set(x) + set(y)
    }

在我看来,最好的答案是“单一表达”部分,因为没有额外的功能是必要的,而且它是短暂的。