问题说明
我的目标是通过使用映射列表来重新映射具有不同深度的嵌套字典的键(本质上是通过交换键)。
我的方法是:
- 将字典扁平化并将其转换为元组列表,
- 重建字典并使用映射列表交换键。
我能做到#1,我正在寻找一个很好的解决方案#2。一般来说,我希望解决方案越通用越好。
<标题>具体案例h1> 有一个N到N-1层的嵌套字典,在给定映射的情况下,前三层需要交换。我的字典的一部分是这样的:raw_dict = {'a':{'b':{'c':[1,2,3]}},
'd':{'e':{'f':{'g':[4,5,6]}}}}
我设法将原始字典扁平化为递归的元组列表,即使用以下函数
def unnest(d, keys=[]):
'''
convert a dictionary to a (ordered) list of tuples
input: dictionary
output: list of tuples
'''
lt = []
for k, v in d.items():
if isinstance(v, dict):
lt.extend(unnest(v, keys + [k]))
else:
lt.append(tuple(keys + [k, v]))
return lt
现在,我有一个长度不等的元组列表,但最长的元素总是比最短的元素长1个元素(基本上每个元组都有N或N-1个元素)。给定上面示例中的raw_dict
,生成的元组列表将如下所示
reform_list = [('a','b','c',[1,2,3]),('d','e','f','g',[4,5,6])]
,其中第一个长度为4 (N-1),第二个长度为5 (N)。
我想实现的是…
…是构建一个函数,该函数基于元组构建一个嵌套字典,而不考虑其长度,但基于如下的映射:
my_map = [2,1,0,3]
函数应该类似于
def nest(my_tuple,my_map):
[do something]
return my_dict
我将在这样的循环中调用函数
for t in reform_list:
n_d = nest(t,my_map)
print(n_d)
循环的预期结果是:
{'c':{'b':{'a':[1,2,3]}}}
{'f':{'e':{'d':{'g':[4,5,6]}}}}
在最后一步…
…我将通过更新它来构建交换后的字典,无论深度如何,递归,从"wanted"中生成的单个字典开始。函数
def update(d, u):
'''
update nested dictionary
input: dict to update (d), update to use (u)
output: updated dict (d)
'''
for k, v in u.items():
if isinstance(v, collections.abc.Mapping):
d[k] = update(d.get(k, {}), v)
else:
d[k] = v
return d
标题>
你可以使用递归:
reform_list = [('a','b','c',[1,2,3]),('d','e','f','g',[4,5,6])]
my_map = [2,1,0,3]
def build_dict(mp, val):
if not mp or len(val) - 1 <= mp[0]:
return val[-1]
return {val[mp[0]]:build_dict(mp[1:],val)}
results = [build_dict(my_map, i) for i in reform_list]
输出:
[{'c': {'b': {'a': [1, 2, 3]}}}, {'f': {'e': {'d': {'g': [4, 5, 6]}}}}]