我想将两个词典融入一个新的词典。
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) 的值。
当前回答
在Python 3.8发布时,将有一个新的选项(计划于2019年10月20日),感谢PEP 572:分配表达式。 新的分配表达式操作员:= 允许您分配副本的结果,并且仍然使用它来呼叫更新,留下组合代码一个单一表达式,而不是两个陈述,改变:
newdict = dict1.copy()
newdict.update(dict2)
到:
(newdict := dict1.copy()).update(dict2)
(newdict := dict1.copy()).update(dict2) or newdict
newdict = {**dict1, **dict2}
脱包方法更清晰(对于任何人都知道一般的脱包,首先,你应该),不需要一个名字的结果(因此,它是更紧密的,当构建一个暂时的,即时转移到一个功能或包含在一个名单 / 双字或类似),并且几乎肯定更快,也是(在CPython上)相当于:
newdict = {}
newdict.update(dict1)
newdict.update(dict2)
它也更可扩展,因为结合三个法则是显而易见的:
newdict = {**dict1, **dict2, **dict3}
(newdict := dict1.copy()).update(dict2), newdict.update(dict3)
或沒有暫時的九個,但以真實的測試,每個九個結果:
(newdict := dict1.copy()).update(dict2) or newdict.update(dict3)
其他回答
最好的版本我可以想象,而不使用复制将是:
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的值,但我不认为很难找到它。
在这里和其他地方绘制想法,我已经理解了一个功能:
def merge(*dicts, **kv):
return { k:v for d in list(dicts) + [kv] for k,v in d.items() }
使用(在Python 3中测试):
assert (merge({1:11,'a':'aaa'},{1:99, 'b':'bbb'},foo='bar')==\
{1: 99, 'foo': 'bar', 'b': 'bbb', 'a': 'aaa'})
assert (merge(foo='bar')=={'foo': 'bar'})
assert (merge({1:11},{1:99},foo='bar',baz='quux')==\
{1: 99, 'foo': 'bar', 'baz':'quux'})
assert (merge({1:11},{1:99})=={1: 99})
你可以用Lambda。
到目前为止,我对列出的解决方案的问题是,在合并词典中,关键“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}
一种替代:
z = x.copy()
z.update(y)
如果你不想转动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风格将可用。