如何递归修改嵌套字典的name键值为父节点拼接路径?
嵌套字典结构中递归拼接节点name路径的实现方法
问题描述
需要处理如下嵌套数据结构:
payload = { "name":"Event1", "events":[ { "name":"A", "data":[ { "name":"subscriptionId", "data_id":0, "data":0 }, { "name":"updateCounter", "data_id":1, "data":0 }, { "name":"noOfMessages", "data_id":2, "data":0 }, { "name":"counter", "data_id":3, "data":0 }, { "name":"resourceElements", "data_id":4, "data":0 }, { "name":"type", "data_id":5, "data":0 }, { "name":"subscription", "data_id":6, "data":0 }, { "name":"element", "data_id":7, "data":[ { "name":"type", "data_id":0, "data":0 }, { "name":"plugLockState", "data_id":1, "data":{ "value":"" } }, { "name":"lockState", "data_id":2, "data":{ "value":"" } }, { "name":"flapState", "data_id":6, "data":{ "value":"" } }, { "name":"plugState", "data_id":3, "data":0 }, { "name":"plugConnectionState", "data_id":4, "data":0 }, { "name":"infrastructureState", "data_id":5, "data":0 } ] } ] } ] }
期望将结构中每个节点的name键值修改为父节点路径拼接的形式,理想结果如下:
{ "name":"Event1", "events":[ { "name":"Event1.A", "data":[ { "name":"Event1.A.subscriptionId", "data_id":0, "data":0 }, { "name":"Event1.A.updateCounter", "data_id":1, "data":0 }, { "name":"Event1.A.noOfMessages", "data_id":2, "data":0 }, { "name":"Event1.A.counter", "data_id":3, "data":0 }, { "name":"Event1.A.resourceElements", "data_id":4, "data":0 }, { "name":"Event1.A.type", "data_id":5, "data":0 }, { "name":"Event1.A.subscription", "data_id":6, "data":0 }, { "name":"Event1.A.element", "data_id":7, "data":[ { "name":"Event1.A.element.type", "data_id":0, "data":0 }, { "name":"Event1.A.element.plugLockState", "data_id":1, "data":{ "value":"" } }, { "name":"Event1.A.element.lockState", "data_id":2, "data":{ "value":"" } }, { "name":"Event1.A.element.flapState", "data_id":6, "data":{ "value":"" } }, { "name":"Event1.A.element.plugState", "data_id":3, "data":0 }, { "name":"Event1.A.element.plugConnectionState", "data_id":4, "data":0 }, { "name":"Event1.A.element.infrastructureState", "data_id":5, "data":0 } ] } ] } ] }
目前已编写如下递归方法,但不清楚如何在递归遍历的同时按需求修改name键值:
def iterate_recursively(dictionary: dict, names=None): if names is None: names = [] for k, v in dictionary.items(): if isinstance(v, dict): iterate_recursively(v) elif isinstance(v, list): for d in v: if isinstance(d, dict): names.append(d["name"]) iterate_recursively(d)
解决方案
你的现有递归逻辑存在两个核心问题:一是没有传递当前的路径前缀,二是缺少修改name的具体逻辑。可以通过以下方式实现需求:
修正后的递归函数
def update_names_recursively(node, parent_path=""): # 处理包含name字段的字典节点 if isinstance(node, dict) and "name" in node: # 拼接新的name:父路径为空时直接用当前name,否则用父路径+当前name if parent_path: node["name"] = f"{parent_path}.{node['name']}" # 将当前节点的完整路径作为子节点的父路径 current_path = node["name"] # 遍历当前节点的所有子元素,递归处理 for key, value in node.items(): if isinstance(value, dict): update_names_recursively(value, current_path) elif isinstance(value, list): for item in value: update_names_recursively(item, current_path) # 调用函数处理目标结构 update_names_recursively(payload)
逻辑说明
- 路径传递:每次递归时,将当前节点的完整路径(已拼接后的
name)作为parent_path传递给子节点,确保子节点能基于父路径生成自己的完整路径。 - 修改时机:优先处理包含
name字段的字典节点,先更新该节点的name值,再以更新后的路径为前缀,处理该节点下的所有子元素(字典或列表中的字典)。 - 列表处理:遇到列表类型的子元素时,遍历列表中的每个项,对其中的字典节点递归执行路径拼接逻辑,确保嵌套在列表中的子节点也能正确生成完整路径。
验证结果
调用上述函数后,payload的结构会完全符合你给出的理想结果,每个节点的name都会是从根节点到当前节点的完整路径拼接。
内容的提问来源于stack exchange,提问作者Mav17
相关产品推荐
相关产品推荐

