Python 保留旧键和新值的合并词典
我正在编写一个Python脚本来解析RSS提要。我想维护一个定期更新的提要条目字典。应该删除提要中不再存在的条目,新条目应该获得默认值,以前看到的条目的值应该保持不变 这最好用例子来解释,我认为:Python 保留旧键和新值的合并词典,python,dictionary,Python,Dictionary,我正在编写一个Python脚本来解析RSS提要。我想维护一个定期更新的提要条目字典。应该删除提要中不再存在的条目,新条目应该获得默认值,以前看到的条目的值应该保持不变 这最好用例子来解释,我认为: >>> old = { ... 'a': 1, ... 'b': 2, ... 'c': 3 ... } >>> new = { ... 'c': 'x', ... 'd': 'y', ... 'e': 'z' ...
>>> old = {
... 'a': 1,
... 'b': 2,
... 'c': 3
... }
>>> new = {
... 'c': 'x',
... 'd': 'y',
... 'e': 'z'
... }
>>> out = some_function(old, new)
>>> out
{'c': 3, 'd': 'y', 'e': 'z'}
以下是我目前的尝试:
def merge_preserving_old_values_and_new_keys(old, new):
out = {}
for k, v in new.items():
out[k] = v
for k, v in old.items():
if k in out:
out[k] = v
return out
这是可行的,但在我看来可能有更好或更聪明的方法
编辑:如果您想测试您的功能:
def my_merge(old, new):
pass
old = {'a': 1, 'b': 2, 'c': 3}
new = {'c': 'x', 'd': 'y', 'e': 'z'}
out = my_merge(old, new)
assert out == {'c': 3, 'd': 'y', 'e': 'z'}
编辑2:
将Martijn Pieters的答案定义为set_merge,bravosierra99的答案定义为loop_merge,并将我的第一次尝试定义为orig_merge,我得到以下计时结果:
>>> setup="""
... old = {'a': 1, 'b': 2, 'c': 3}
... new = {'c': 'x', 'd': 'y', 'e': 'z'}
... from __main__ import set_merge, loop_merge, orig_merge
... """
>>> timeit.timeit('set_merge(old, new)', setup=setup)
3.4415210600000137
>>> timeit.timeit('loop_merge(old, new)', setup=setup)
1.161155690000669
>>> timeit.timeit('orig_merge(old, new)', setup=setup)
1.1776735319999716
我觉得这很奇怪,因为我没想到dictionary-view方法会慢得多。这应该更有效,因为您不再遍历整个old.items。此外,由于没有覆盖某些值,因此更清楚地知道您试图以这种方式做什么
for k, v in new.items():
if k in old.keys():
out[k] = old[k]
else:
out[k] = v
return out
这应该更有效,因为您不再遍历整个old.items。此外,由于没有覆盖某些值,因此更清楚地知道您试图以这种方式做什么
for k, v in new.items():
if k in old.keys():
out[k] = old[k]
else:
out[k] = v
return out
字典有集的作用。使用这些选项可以获得新旧之间的交点:
def merge_preserving_old_values_and_new_keys(old, new):
result = new.copy()
result.update((k, old[k]) for k in old.viewkeys() & new.viewkeys())
return result
上面使用了Python2语法;如果使用Python 3,请使用old.keys和new.keys,以获得相同的结果:
def merge_preserving_old_values_and_new_keys(old, new):
# Python 3 version
result = new.copy()
result.update((k, old[k]) for k in old.keys() & new.keys())
return result
上面以new中的所有键值对为起点,然后为出现在两者中的任何键添加old的值
演示:
请注意,该函数与您的版本一样,会生成一个新的字典,尽管键和值对象是共享的;这是一个肤浅的副本
如果您不需要新词典来做任何其他事情,您也可以在适当的位置更新新词典:
def merge_preserving_old_values_and_new_keys(old, new):
new.update((k, old[k]) for k in old.viewkeys() & new.viewkeys())
return new
您还可以使用一行文字的听写理解来构建新词典:
def merge_preserving_old_values_and_new_keys(old, new):
return {k: old[k] if k in old else v for k, v in new.items()}
字典有集的作用。使用这些选项可以获得新旧之间的交点:
def merge_preserving_old_values_and_new_keys(old, new):
result = new.copy()
result.update((k, old[k]) for k in old.viewkeys() & new.viewkeys())
return result
上面使用了Python2语法;如果使用Python 3,请使用old.keys和new.keys,以获得相同的结果:
def merge_preserving_old_values_and_new_keys(old, new):
# Python 3 version
result = new.copy()
result.update((k, old[k]) for k in old.keys() & new.keys())
return result
上面以new中的所有键值对为起点,然后为出现在两者中的任何键添加old的值
演示:
请注意,该函数与您的版本一样,会生成一个新的字典,尽管键和值对象是共享的;这是一个肤浅的副本
如果您不需要新词典来做任何其他事情,您也可以在适当的位置更新新词典:
def merge_preserving_old_values_and_new_keys(old, new):
new.update((k, old[k]) for k in old.viewkeys() & new.viewkeys())
return new
您还可以使用一行文字的听写理解来构建新词典:
def merge_preserving_old_values_and_new_keys(old, new):
return {k: old[k] if k in old else v for k, v in new.items()}
我不是100%将这些信息添加到讨论中的最佳方式:如有必要,请随意编辑/重新发布 下面是这里讨论的所有方法的计时结果
from timeit import timeit
def loop_merge(old, new):
out = {}
for k, v in new.items():
if k in old:
out[k] = old[k]
else:
out[k] = v
return out
def set_merge(old, new):
out = new.copy()
out.update((k, old[k]) for k in old.keys() & new.keys())
return out
def comp_merge(old, new):
return {k: old[k] if k in old else v for k, v in new.items()}
def orig_merge(old, new):
out = {}
for k, v in new.items():
out[k] = v
for k, v in old.items():
if k in out:
out[k] = v
return out
old = {'a': 1, 'b': 2, 'c': 3}
new = {'c': 'x', 'd': 'y', 'e': 'z'}
out = {'c': 3, 'd': 'y', 'e': 'z'}
assert loop_merge(old, new) == out
assert set_merge(old, new) == out
assert comp_merge(old, new) == out
assert orig_merge(old, new) == out
setup = """
from __main__ import old, new, loop_merge, set_merge, comp_merge, orig_merge
"""
for a in ['loop', 'set', 'comp', 'orig']:
time = timeit('{}_merge(old, new)'.format(a), setup=setup)
print('{}: {}'.format(a, time))
size = 10**4
large_old = {i: 'old' for i in range(size)}
large_new = {i: 'new' for i in range(size//2, size)}
setup = """
from __main__ import large_old, large_new, loop_merge, set_merge, comp_merge, orig_merge
"""
for a in ['loop', 'set', 'comp', 'orig']:
time = timeit('{}_merge(large_old, large_new)'.format(a), setup=setup)
print('{}: {}'.format(a, time))
优胜者是改进的循环方法
$ python3 merge.py
loop: 0.7791572390015062 # small dictionaries
set: 3.1920828100010112
comp: 1.1180207730030816
orig: 1.1681104259987478
loop: 927.2149353210007 # large dictionaries
set: 1696.8342713210004
comp: 902.039078668
orig: 1373.0389542560006
我很失望,因为dictionary view/set操作方法要酷得多
对于较大的词典10^4项,词典理解方法领先于改进的循环方法,远远领先于原始方法。设置操作方法的执行速度仍然最慢。我不是100%将此信息添加到讨论中的最佳方法:如有必要,请随意编辑/重新发布 下面是这里讨论的所有方法的计时结果
from timeit import timeit
def loop_merge(old, new):
out = {}
for k, v in new.items():
if k in old:
out[k] = old[k]
else:
out[k] = v
return out
def set_merge(old, new):
out = new.copy()
out.update((k, old[k]) for k in old.keys() & new.keys())
return out
def comp_merge(old, new):
return {k: old[k] if k in old else v for k, v in new.items()}
def orig_merge(old, new):
out = {}
for k, v in new.items():
out[k] = v
for k, v in old.items():
if k in out:
out[k] = v
return out
old = {'a': 1, 'b': 2, 'c': 3}
new = {'c': 'x', 'd': 'y', 'e': 'z'}
out = {'c': 3, 'd': 'y', 'e': 'z'}
assert loop_merge(old, new) == out
assert set_merge(old, new) == out
assert comp_merge(old, new) == out
assert orig_merge(old, new) == out
setup = """
from __main__ import old, new, loop_merge, set_merge, comp_merge, orig_merge
"""
for a in ['loop', 'set', 'comp', 'orig']:
time = timeit('{}_merge(old, new)'.format(a), setup=setup)
print('{}: {}'.format(a, time))
size = 10**4
large_old = {i: 'old' for i in range(size)}
large_new = {i: 'new' for i in range(size//2, size)}
setup = """
from __main__ import large_old, large_new, loop_merge, set_merge, comp_merge, orig_merge
"""
for a in ['loop', 'set', 'comp', 'orig']:
time = timeit('{}_merge(large_old, large_new)'.format(a), setup=setup)
print('{}: {}'.format(a, time))
优胜者是改进的循环方法
$ python3 merge.py
loop: 0.7791572390015062 # small dictionaries
set: 3.1920828100010112
comp: 1.1180207730030816
orig: 1.1681104259987478
loop: 927.2149353210007 # large dictionaries
set: 1696.8342713210004
comp: 902.039078668
orig: 1373.0389542560006
我很失望,因为dictionary view/set操作方法要酷得多
对于较大的词典10^4项,词典理解方法领先于改进的循环方法,远远领先于原始方法。设置操作方法的执行速度仍然最慢。这会改变原有的新操作。不要在dict.keys中使用if键;在Python2中,每次通过循环创建一个全新的list对象,然后扫描该列表以查看键是否在其中。在Python3中,每次都创建一个dictionary视图对象,然后进行O1常量时间成员身份测试。所有这一切都比仅仅键入dict要昂贵,因此放弃.keys调用,该调用在不创建新对象的情况下执行O1测试。这会改变新的位置。不要在dict.keys中使用if-key;在Python2中,每次通过循环创建一个全新的list对象,然后扫描该列表以查看键是否在其中。在Python3中,每次都创建一个dictionary视图对象,然后进行O1常量时间成员身份测试。所有这些都比只键入dict要昂贵,因此放弃.keys调用,它在不创建新对象的情况下执行O1测试。这确实更清晰,而且肯定是对我尝试的改进!missing:out={}此处相同:不要在dict.keys中使用if键;在Python2中,每次通过循环创建一个全新的list对象,然后扫描该列表以查看键是否在其中。在Python3中,每次创建一个dictionary视图对象,然后创建一个O1常量时间memb
完成了ership测试。所有这一切都比只键入dict要昂贵,因此放弃.keys调用,该调用在不创建新对象的情况下执行O1测试。事实上,@MartijnPieters,删除.keys会将我的时间从~1.2更改为0.8。这确实更清晰,而且肯定是对我尝试的改进!missing:out={}此处相同:不要在dict.keys中使用if键;在Python2中,每次通过循环创建一个全新的list对象,然后扫描该列表以查看键是否在其中。在Python3中,每次都创建一个dictionary视图对象,然后进行O1常量时间成员身份测试。所有这些都比只键入dict要昂贵,因此放弃.keys调用,该调用在不创建新对象的情况下执行O1测试。事实上,@MartijnPieters,删除.keys会改变我的时间,它的结果从~1.2变为0.8。输入字典相当小。大的输入会发生什么?有趣;我期望dict comp比普通循环更好,dict view结果令人失望,但实际上并不令人惊讶,因为它们将普通循环与字典副本相结合。输入字典相当小。大的输入会发生什么?有趣;我期望dict comp比普通循环更好,dict view结果令人失望,但实际上并不令人惊讶,因为它们将普通循环与字典副本结合起来。