我想将两个词典融入一个新的词典。
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.5 (PEP 448) 允许更好的合成选项:
x = {'a': 1, 'b': 1}
y = {'a': 2, 'c': 2}
final = {**x, **y}
final
# {'a': 2, 'b': 1, 'c': 2}
或甚至
final = {'a': 1, 'b': 1, **x, **y}
在 Python 3.9 中,您也可以使用 <unk>和 <unk>= 与 PEP 584 的下面的示例
d = {'spam': 1, 'eggs': 2, 'cheese': 3}
e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}
d | e
# {'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}
其他回答
重复 / 深度更新 a dict
def deepupdate(original, update):
"""
Recursively update a dict.
Subdict's won't be overwritten but also updated.
"""
for key, value in original.iteritems():
if key not in update:
update[key] = value
elif isinstance(value, dict):
deepupdate(value, update[key])
return update
示威:
pluto_original = {
'name': 'Pluto',
'details': {
'tail': True,
'color': 'orange'
}
}
pluto_update = {
'name': 'Pluutoo',
'details': {
'color': 'blue'
}
}
print deepupdate(pluto_original, pluto_update)
结果:
{
'name': 'Pluutoo',
'details': {
'color': 'blue',
'tail': True
}
}
谢谢Radnaw的编辑。
z1 = dict(x.items() + y.items())
z2 = dict(x, **y)
在我的机器上,至少(一个相当常见的x86_64运行Python 2.5.2),替代Z2不仅更短,更简单,而且更快。
% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z1=dict(x.items() + y.items())'
100000 loops, best of 3: 5.67 usec per loop
% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z2=dict(x, **y)'
100000 loops, best of 3: 1.53 usec per loop
示例2:不超越的字典,将252条短线地图到整条,反之亦然:
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z1=dict(x.items() + y.items())'
1000 loops, best of 3: 260 usec per loop
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z2=dict(x, **y)'
10000 loops, best of 3: 26.9 usec per loop
z2赢得了大约10的因素,这在我的书中是一个相当大的胜利!
在比较这两个之后,我想知道 z1 的不良性能是否可以归功于构建两个项目列表的顶端,这反过来导致我想知道这个变量是否会更好地工作:
from itertools import chain
z3 = dict(chain(x.iteritems(), y.iteritems()))
% python -m timeit -s 'from itertools import chain; from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z3=dict(chain(x.iteritems(), y.iteritems()))'
10000 loops, best of 3: 66 usec per loop
z0 = dict(x)
z0.update(y)
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z0=dict(x); z0.update(y)'
10000 loops, best of 3: 26.9 usec per loop
你也可以这样写作
z0 = x.copy()
z0.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风格将可用。
x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}
>>> z
{'a': 1, 'b': 3, 'c': 4}
z = {**x, **y}
z = {**x, 'foo': 1, 'bar': 2, **y}
>>> z
{'a': 1, 'b': 3, 'foo': 1, 'bar': 2, 'c': 4}
z = x.copy()
z.update(y) # which returns None since it mutates z
def merge_two_dicts(x, y):
"""Given two dictionaries, merge them into a new dict as a shallow copy."""
z = x.copy()
z.update(y)
return z
z = merge_two_dicts(x, y)
def merge_dicts(*dict_args):
"""
Given any number of dictionaries, shallow copy and merge into a new dict,
precedence goes to key-value pairs in latter dictionaries.
"""
result = {}
for dictionary in dict_args:
result.update(dictionary)
return result
z = merge_dicts(a, b, c, d, e, f, g)
和 g 的关键值对将先行于字典 a 到 f 等。
z = dict(x.items() + y.items())
>>> c = dict(a.items() + b.items())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'
同样,在 Python 3 (viewitems() 在 Python 2.7) 中采取元素的合并也会失败,当值是不可破坏的对象(如列表,例如)。即使您的值是可破坏的,因为套件是无形的,行为与先例无定义。
>>> c = dict(a.items() | b.items())
>>> x = {'a': []}
>>> y = {'b': []}
>>> dict(x.items() | y.items())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> x = {'a': 2}
>>> y = {'a': 1}
>>> dict(x.items() | y.items())
{'a': 2}
另一个你不应该使用的黑客:
z = dict(x, **y)
字典的目的是采取可触摸的密钥(例如,frozensets或tuples),但这种方法在Python 3中失败,当密钥不是线条时。
>>> c = dict(a, **b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings
和
dict(a=1, b=10, c=11)
{'a': 1, 'b': 10, 'c': 11}
>>> foo(**{('a', 'b'): None})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() keywords must be strings
>>> dict(**{('a', 'b'): None})
{('a', 'b'): None}
我的答案: merge_two_dicts(x,y)实际上对我来说看起来更清楚,如果我们实际上对可读性感兴趣。
from copy import deepcopy
def dict_of_dicts_merge(x, y):
z = {}
overlapping_keys = x.keys() & y.keys()
for key in overlapping_keys:
z[key] = dict_of_dicts_merge(x[key], y[key])
for key in x.keys() - overlapping_keys:
z[key] = deepcopy(x[key])
for key in y.keys() - overlapping_keys:
z[key] = deepcopy(y[key])
return z
>>> x = {'a':{1:{}}, 'b': {2:{}}}
>>> y = {'b':{10:{}}, 'c': {11:{}}}
>>> dict_of_dicts_merge(x, y)
{'b': {2: {}, 10: {}}, 'a': {1: {}}, 'c': {11: {}}}
{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7
dict((k, v) for d in dicts for k, v in d.items()) # iteritems in Python 2
from itertools import chain
z = dict(chain(x.items(), y.items())) # iteritems in Python 2
from timeit import repeat
from itertools import chain
x = dict.fromkeys('abcdefg')
y = dict.fromkeys('efghijk')
def merge_two_dicts(x, y):
z = x.copy()
z.update(y)
return z
min(repeat(lambda: {**x, **y}))
min(repeat(lambda: merge_two_dicts(x, y)))
min(repeat(lambda: {k: v for d in (x, y) for k, v in d.items()}))
min(repeat(lambda: dict(chain(x.items(), y.items()))))
min(repeat(lambda: dict(item for d in (x, y) for item in d.items())))
>>> min(repeat(lambda: {**x, **y}))
1.0804965235292912
>>> min(repeat(lambda: merge_two_dicts(x, y)))
1.636518670246005
>>> min(repeat(lambda: {k: v for d in (x, y) for k, v in d.items()}))
3.1779992282390594
>>> min(repeat(lambda: dict(chain(x.items(), y.items()))))
2.740647904574871
>>> min(repeat(lambda: dict(item for d in (x, y) for item in d.items())))
4.266070580109954
$ uname -a
Linux nixos 4.19.113 #1-NixOS SMP Wed Mar 25 07:06:15 UTC 2020 x86_64 GNU/Linux
词典中的资源
在您的情况下,您可以:
z = dict(list(x.items()) + list(y.items()))
因此,如您所需,将最终定位定位为z,并使关键b的值由第二(y)定位的值正确上调:
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10}
如果您使用 Python 2, 您甚至可以删除列表() 通话。
>>> z = dict(x.items() + y.items())
>>> z
{'a': 1, 'c': 11, 'b': 10}
如果您使用 Python 版本 3.9.0a4 或更高版本,则可以直接使用:
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = x | y
print(z)
{'a': 1, 'c': 11, 'b': 10}