如何通过递归用.拼接字符串变量?嵌套字典扁平化问题
递归实现嵌套字典的扁平化(点号拼接键名)
问题场景
我写了一个用来扁平化嵌套字典的Python函数flat:
def flat(errors: dict) -> dict: result = {} def inner(errors, key=None): if type(errors) is dict: for k, v in errors.items(): inner(v, k) elif type(errors) is list: for obj in errors: inner(obj) else: result.update({key: errors}) inner(errors) return result
测试数据如下:
errors = { "last_name": "Имя должно состоять из букв", "birth_place": { "address": { "parts": [ { "0": { "id": "Неверный идентификатор", }, }, { "1": { "id": "Неверный идентификатор", }, }, ], }, }, "groups": [ { "1": "Группа workers не существует", }, ], }
我期望得到的输出是:
{ "last_name": "Имя должно состоять из букв", "birth_place.address.parts.0.id": "Неверный идентификатор", "birth_place.address.parts.1.id": "Неверный идентификатор", "groups.1": "Группа workers не существует", }
但实际输出却是:
{'last_name': 'Имя должно состоять из букв', 'id': 'Неверный идентификатор', '1': 'Группа workers не существует'}
请问怎么通过递归实现用点号拼接完整的键路径?我对递归思维有点困惑。
问题分析
原函数的核心问题是:递归时只传递了当前层级的单个键,没有把之前层级的键路径传递下去。导致遇到叶子节点时,只能拿到最后一级的键名,重复的键会直接覆盖,最终丢失了完整的嵌套路径。
修正后的递归实现
我们需要在递归过程中维护当前已经拼接好的路径前缀,每进入一层嵌套(字典或列表),就把当前节点的标识(字典的键/列表的索引)拼接到路径上,直到遇到叶子节点时,用完整路径作为键存入结果:
def flat(errors: dict) -> dict: result = {} def inner(data, current_path=""): # 处理字典类型:遍历键值对,拼接路径 if isinstance(data, dict): for k, v in data.items(): # 如果当前路径为空,直接用当前键;否则用点号拼接 new_path = f"{current_path}.{k}" if current_path else k inner(v, new_path) # 处理列表类型:遍历元素,用索引作为路径的一部分 elif isinstance(data, list): for idx, item in enumerate(data): new_path = f"{current_path}.{idx}" if current_path else str(idx) inner(item, new_path) # 处理叶子节点:将完整路径和值存入结果 else: result[current_path] = data inner(errors) return result
递归思路解释
递归的关键在于每一层调用都携带当前的上下文信息(这里就是已构建的路径),具体逻辑:
- 初始调用时,
current_path为空字符串,代表还没有进入任何嵌套层级。 - 遇到字典:遍历每个键,把当前键拼接到已有路径后面(用点号分隔),然后递归处理对应的值。
- 遇到列表:遍历每个元素,把元素的索引转为字符串拼接到已有路径后面,递归处理元素内容。
- 遇到非字典非列表的叶子值:把当前的完整路径作为键,叶子值作为值存入结果字典。
这样就能保证每个叶子节点都能对应到从根节点到它的完整路径,不会出现键覆盖的问题。
内容的提问来源于stack exchange,提问作者user21139240
相关产品推荐
相关产品推荐

