概述
下面的方法将字典的深度合并问题细分为:
使用A的参数化浅归并函数merge(f)(A,b)
函数f归并两个字典a和b
与归并一起使用的递归归并函数f
实现
合并两个(非嵌套的)字典的函数可以用很多种方式编写。我个人喜欢
def merge(f):
def merge(a,b):
keys = a.keys() | b.keys()
return {key:f(a.get(key), b.get(key)) for key in keys}
return merge
定义一个合适的递归归并函数f的一个好方法是使用multidispatch,它允许定义函数根据参数的类型沿着不同的路径求值。
from multipledispatch import dispatch
#for anything that is not a dict return
@dispatch(object, object)
def f(a, b):
return b if b is not None else a
#for dicts recurse
@dispatch(dict, dict)
def f(a,b):
return merge(f)(a,b)
例子
要合并两个嵌套字典,只需使用merge(f),例如:
dict1 = {1:{"a":"A"},2:{"b":"B"}}
dict2 = {2:{"c":"C"},3:{"d":"D"}}
merge(f)(dict1, dict2)
#returns {1: {'a': 'A'}, 2: {'b': 'B', 'c': 'C'}, 3: {'d': 'D'}}
注:
这种方法的优点是:
该函数由较小的函数构建而成,每个函数只做一件事
这使得代码更容易推理和测试
这种行为不是硬编码的,但可以根据需要进行更改和扩展,从而提高代码重用(参见下面的示例)。
定制
一些答案还考虑了包含列表的字典,例如其他(可能嵌套的)字典。在这种情况下,可能需要映射列表并根据位置合并它们。这可以通过在归并函数f中添加另一个定义来实现:
import itertools
@dispatch(list, list)
def f(a,b):
return [merge(f)(*arg) for arg in itertools.zip_longest(a, b)]