来自元组列表的不同深度嵌套字典
varying depth nested dict from list of tuples
问题陈述
我的目标是通过使用映射列表重新映射具有不同深度的嵌套字典的键(主要是通过交换它们)。
我的做法是:
- 扁平化字典并将其变成元组列表,
- 重建字典并使用映射列表交换键。
我能够做到#1,我正在为#2 寻找一个好的解决方案。一般来说,我希望解决方案尽可能通用。
具体案例
我有一个 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]}}}}
最后一步...
...我将通过更新来构建交换字典,无论深度如何,递归,从使用以下函数在“通缉”函数中生成的单个字典开始
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]}}}}]
问题陈述
我的目标是通过使用映射列表重新映射具有不同深度的嵌套字典的键(主要是通过交换它们)。
我的做法是:
- 扁平化字典并将其变成元组列表,
- 重建字典并使用映射列表交换键。
我能够做到#1,我正在为#2 寻找一个好的解决方案。一般来说,我希望解决方案尽可能通用。
具体案例
我有一个 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]}}}}
最后一步...
...我将通过更新来构建交换字典,无论深度如何,递归,从使用以下函数在“通缉”函数中生成的单个字典开始
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]}}}}]