使用anytree根据DataFrame父子关系构建树时重复子节点丢失如何解决
使用anytree生成脚本依赖树时重复子节点丢失问题
我当前尝试基于存储了需按特定顺序执行的脚本的DataFrame生成树图,脚本执行顺序由parent/child关系决定,但生成结果中的子节点数量不正确。我的DataFrame如下所示:
【DataFrame结构示意图】
目前我已编写的代码如下:
from anytree import Node, RenderTree def add_nodes(nodes, parent, child): if parent not in nodes: nodes[parent] = Node(parent) if child not in nodes: nodes[child] = Node(child) nodes[child].parent = nodes[parent] nodes = {} for parent, child in zip(df["parent_script"],df["child_script"]): add_nodes(nodes, parent, child) roots = list(df[~df["parent_script"].isin(df["child_script"])]["parent_script"].unique()) for root in roots: for pre, _, node in RenderTree(nodes[root]): print("%s%s" % (pre, node.name))
运行后3个根节点和多个父节点都能正常展示,但子节点只要被添加过一次之后就会丢失。我得到的运行结果如下:
【运行结果示意图】
我认为是如下逻辑导致我没有得到预期的完整结果:
if child not in nodes: nodes[child] = Node(child) nodes[child].parent = nodes[parent]
我需要所有子节点都能正确展示在树中,例如第三个根节点(00_06_MaxBIS_v2-2.sql)当前仅显示子节点00_07_AnlagenDatenLaden_v1-7.sql,缺失了子节点00_Gebietsstrukturen_v1-2.sql。请问有没有方法可以在树中正确保留重复子节点?要得到预期结果应该使用什么逻辑?
解答
根因分析
anytree框架中每个Node实例仅支持绑定一个父节点。你当前的实现用脚本名作为全局唯一key缓存Node实例,当同一个脚本作为多个父节点的子节点时,后续的父节点赋值操作会直接覆盖原有的父关联,导致之前的父节点下丢失该子节点。
解决方法
不要复用子节点实例,每次遇到新的父子关联都创建独立的子节点实例即可。如果需要后续识别节点对应的脚本,可以给Node新增自定义属性存储脚本名,不需要依赖全局唯一的节点实例缓存。
修正后代码
from anytree import Node, RenderTree # 仅缓存根节点/父节点实例,避免重复创建同级父节点 parent_node_map = {} for parent_name in df["parent_script"].unique(): if parent_name not in parent_node_map: parent_node_map[parent_name] = Node(parent_name, script_name=parent_name) # 遍历所有父子关系,每次创建独立的子节点实例 for _, row in df.iterrows(): parent_node = parent_node_map[row["parent_script"]] # 每次生成新的子节点,不做全局缓存 Node(row["child_script"], script_name=row["child_script"], parent=parent_node) # 输出树结构逻辑不变 roots = df[~df["parent_script"].isin(df["child_script"])]["parent_script"].unique() for root_name in roots: for pre, _, node in RenderTree(parent_node_map[root_name]): print(f"{pre}{node.name}")
如果后续需要对相同脚本名的节点做批量操作,遍历全树节点通过script_name属性筛选即可。
内容的提问来源于stack exchange,提问作者Erik D
相关产品推荐
相关产品推荐

