You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python/JS将非嵌套JSON转换为树形图适用的嵌套JSON结构

问题说明

现有扁平化节点列表(问题中给出的为伪JSON格式,不符合标准JSON语法,实际使用时需先将键、字符串值补充双引号转为合法结构),节点间通过name字段做关联引用,直接传入绘图逻辑会生成网状非树形结构,需要转换为单根标准树形结构。
注:问题示例中原始数据main节点的children字段里的fun3为笔误,实际应为func,和最终输出结构匹配。

转换核心逻辑
  • 以节点name作为唯一标识,先遍历全量显式定义的节点建立全局映射表
  • 遍历所有节点的children字段收集引用节点,未显式定义的引用节点自动补全为{name: 节点名, children: null}的基础结构
  • 统计每个节点的入度(被其他节点引用为子节点的次数),入度为0的节点即为整棵树的根节点
  • 从根节点开始递归标准化结构,将children里的名称引用替换为对应的节点对象,过程中标记已访问节点避免循环递归
代码实现

Python 版本

def convert_to_tree(raw_nodes):
    node_map = {}
    # 登记所有显式定义的节点
    for node in raw_nodes:
        node_map[node["name"]] = node.copy()

    ref_set = set()
    # 收集所有子节点引用,补全缺失节点
    for node in raw_nodes:
        children = node.get("children")
        if not children:
            node["children"] = None
            continue
        # 统一把子节点转为列表格式处理
        child_names = [children] if isinstance(children, str) else children
        for child_name in child_names:
            ref_set.add(child_name)
            if child_name not in node_map:
                node_map[child_name] = {"name": child_name, "children": None}

    # 查找入度为0的根节点
    root_name = None
    for name in node_map.keys():
        if name not in ref_set:
            root_name = name
            break

    visited = set()
    def standardize(node):
        if node["name"] in visited:
            return
        visited.add(node["name"])
        children = node.get("children")
        if not children:
            node["children"] = None
            return
        # 将名称引用替换为实际节点对象
        if isinstance(children, str):
            child_list = [node_map[children]]
        else:
            child_list = [node_map[c] for c in children]
        node["children"] = child_list
        for child in child_list:
            standardize(child)

    root = node_map[root_name]
    standardize(root)
    return root

# 测试用例(对应问题给出的原始数据)
raw_data = [
    {"name": "func1", "children": "func"},
    {"name": "func2", "children": "func"},
    {"name": "main", "children": ["func1", "func2", "func"]}
]
standard_tree = convert_to_tree(raw_data)

JavaScript 版本

function convertToTree(rawNodes) {
    const nodeMap = {};
    // 登记所有显式定义的节点
    rawNodes.forEach(node => {
        nodeMap[node.name] = {...node};
    });

    const refSet = new Set();
    // 收集所有子节点引用,补全缺失节点
    rawNodes.forEach(node => {
        const children = node.children;
        if (!children) {
            node.children = null;
            return;
        }
        const childNames = Array.isArray(children) ? children : [children];
        childNames.forEach(childName => {
            refSet.add(childName);
            if (!nodeMap[childName]) {
                nodeMap[childName] = {name: childName, children: null};
            }
        });
    });

    // 查找入度为0的根节点
    let rootName = null;
    for (const name of Object.keys(nodeMap)) {
        if (!refSet.has(name)) {
            rootName = name;
            break;
        }
    }

    const visited = new Set();
    function standardize(node) {
        if (visited.has(node.name)) return;
        visited.add(node.name);
        const children = node.children;
        if (!children) {
            node.children = null;
            return;
        }
        // 将名称引用替换为实际节点对象
        const childList = Array.isArray(children)
            ? children.map(c => nodeMap[c])
            : [nodeMap[children]];
        node.children = childList;
        childList.forEach(child => standardize(child));
    }

    const root = nodeMap[rootName];
    standardize(root);
    return root;
}

// 测试用例(对应问题给出的原始数据)
const rawData = [
    {name: "func1", children: "func"},
    {name: "func2", children: "func"},
    {name: "main", children: ["func1", "func2", "func"]}
];
const standardTree = convertToTree(rawData);
适配说明
  • 如果场景下存在多个入度为0的节点,可以创建一个虚拟根节点,将所有无入度节点挂载到虚拟根下,保证单根结构符合树形组件要求
  • 如果业务要求严格单父节点(禁止节点共享,彻底避免网状结构),处理子节点时对已访问过的节点做深拷贝后再挂载即可
  • 代码默认支持任意层级嵌套,循环引用场景下不会出现死递归

内容的提问来源于stack exchange,提问作者vincand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 09:45:36