我想将两个词典融入一个新的词典。
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': 3, 'c': 4}
z = merge(x, y)
>>> z
{'a': 1, 'b': 3, 'c': 4}
每当两个字典中都有一个关键 k 时,只应保留 y(k) 的值。
当前回答
深深的定律:
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}")
其他回答
这是如此愚蠢,即.update 没有回报,我只是使用一个简单的助理功能来解决问题:
def merge(dict1,*dicts):
for dict2 in dicts:
dict1.update(dict2)
return dict1
例子:
merge(dict1,dict2)
merge(dict1,dict2,dict3)
merge(dict1,dict2,dict3,dict4)
merge({},dict1,dict2) # this one returns a new copy
我认为我的丑陋的单线只需要在这里。
z = next(z.update(y) or z for z in [x.copy()])
# or
z = (lambda z: z.update(y) or z)(x.copy())
单一表达,永远不要敢用它。
我知道Python 3有这个 {**x, **y} 事物,它是正确的事情使用(以及转到Python 3 如果你仍然有Python 2是正确的事情)。
如果你不想转动X,
x.update(y) or x
(x.update(y), x)[-1]
如果你还没有X在变量,你可以使用Lambda做一个地方,而不使用任务声明,这意味着使用Lambda作为一个Let表达,这是一个常见的技术在功能语言,但可能是无神论的。
(lambda x: x.update(y) or x)({'a': 1, 'b': 2})
(x := {'a': 1, 'b': 2}).update(y) or x
(lambda x={'a': 1, 'b': 2}: x.update(y) or x)()
如果你想要一个副本,PEP 584 风格 x <unk> y 是最 Pythonic 的 3.9+. 如果你需要支持更古老的版本,PEP 448 风格 {**x, **y} 是最容易的 3.5+. 但如果它不在你的(甚至更古老的) Python 版本,让表达模式也在这里工作。
(lambda z=x.copy(): z.update(y) or z)()
(当然,这可能相当于(z := x.copy())。更新(y)或z,但如果您的Python版本足够新,那么PEP 448风格将可用。
最好的版本我可以想象,而不使用复制将是:
from itertools import chain
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dict(chain(x.iteritems(), y.iteritems()))
它比 dict(x.items() + y.items()) 更快,但不像 n = copy(a); n.update(b),至少在 CPython 上。
我个人最喜欢这个版本,因为它在一个单一的功能合成中描述了我想要的东西相当好,唯一的小问题是,它并不完全显而易见,Y的值超过X的值,但我不认为很难找到它。
另一个,更细致的选择:
z = dict(x, **y)
注意:这已成为一个受欢迎的答案,但重要的是要指出的是,如果 y 有任何不紧密的密钥,事实上,这完全是CPython实施细节的滥用,并且它不在Python 3或PyPy,IronPython,或Jython工作。