一个递归案例

// JSON 数据
const data ={
    "nodes": [
        {
            "id": "aee0e753-3643-452a-9fb5-9d2dda953244",
            "type": "semantic_segmentation",
            "title": "语义分割",
            "subtitle": "语义分割",
            "position": {
                "x": 49840,
                "y": 49810
            },
            "level": 0,
            "branch": 0,
            "properties": {
                "attrs": {
                    "model_id": {
                        "type": "string",
                        "description": "模型ID",
                        "required": true,
                        "name": "模型ID"
                    }
                },
                "input_params": {
                    "image": {
                        "type": "image",
                        "description": "图片",
                        "required": true,
                        "name": "图片"
                    }
                },
                "output_params": {
                    "predictions": {
                        "type": "object",
                        "description": "分割结果",
                        "required": true,
                        "name": "预测结果"
                    }
                }
            },
            "iconType": "semantic_segmentation"
        },
        {
            "id": "50865899-f9dd-4417-973d-2ccce4c994ef",
            "type": "image_clip",
            "title": "图片裁剪",
            "subtitle": "图片裁剪",
            "position": {
                "x": 49840,
                "y": 49960
            },
            "level": 1,
            "branch": 0,
            "properties": {
                "attrs": {
                    "x": {
                        "type": "number",
                        "description": "x坐标",
                        "required": true,
                        "name": "x坐标"
                    },
                    "y": {
                        "type": "number",
                        "description": "y坐标",
                        "required": true,
                        "name": "y坐标"
                    },
                    "width": {
                        "type": "number",
                        "description": "宽度",
                        "required": true,
                        "name": "宽度"
                    },
                    "height": {
                        "type": "number",
                        "description": "高度",
                        "required": true,
                        "name": "高度"
                    }
                },
                "input_params": {
                    "image": {
                        "type": "image",
                        "description": "图片",
                        "required": true,
                        "name": "图片"
                    }
                },
                "output_params": {
                    "image": {
                        "type": "image",
                        "description": "裁剪后的图片",
                        "required": true,
                        "name": "裁剪后的图片"
                    }
                }
            },
            "iconType": "image_clip"
        },
        {
            "id": "8ca5e332-3889-40bc-9991-c68ded5af390",
            "type": "visualize",
            "title": "推理结果可视化",
            "subtitle": "推理结果可视化",
            "position": {
                "x": 49840,
                "y": 50560
            },
            "level": 5,
            "branch": 0,
            "properties": {
                "attrs": {
                    "color": {
                        "type": "string",
                        "description": "颜色",
                        "required": true,
                        "default": "#00FF00",
                        "name": "颜色"
                    },
                    "line_width": {
                        "type": "number",
                        "description": "线宽",
                        "required": true,
                        "default": 2,
                        "name": "线宽"
                    }
                },
                "input_params": {
                    "predictions": {
                        "type": "object",
                        "description": "推理结果",
                        "required": true,
                        "name": "推理结果"
                    },
                    "image": {
                        "type": "image",
                        "description": "图片",
                        "required": true,
                        "name": "图片"
                    }
                },
                "output_params": {
                    "image": {
                        "type": "image",
                        "description": "可视化结果",
                        "required": true,
                        "name": "可视化结果"
                    }
                }
            },
            "iconType": "visualize"
        },
        {
            "id": "32fda8fa-cdea-48aa-bb4e-ee578a0f5bd5",
            "type": "image_clip",
            "title": "图片裁剪_1",
            "subtitle": "图片裁剪",
            "position": {
                "x": 49840,
                "y": 50110
            },
            "level": 2,
            "branch": 0,
            "properties": {
                "attrs": {
                    "x": {
                        "type": "number",
                        "description": "x坐标",
                        "required": true,
                        "name": "x坐标"
                    },
                    "y": {
                        "type": "number",
                        "description": "y坐标",
                        "required": true,
                        "name": "y坐标"
                    },
                    "width": {
                        "type": "number",
                        "description": "宽度",
                        "required": true,
                        "name": "宽度"
                    },
                    "height": {
                        "type": "number",
                        "description": "高度",
                        "required": true,
                        "name": "高度"
                    }
                },
                "input_params": {
                    "image": {
                        "type": "image",
                        "description": "图片",
                        "required": true,
                        "name": "图片"
                    }
                },
                "output_params": {
                    "image": {
                        "type": "image",
                        "description": "裁剪后的图片",
                        "required": true,
                        "name": "裁剪后的图片"
                    }
                }
            },
            "iconType": "image_clip"
        },
        {
            "id": "f65b6774-ebeb-4d62-bb52-ca0f2aa69636",
            "type": "visualize",
            "title": "推理结果可视化_1",
            "subtitle": "推理结果可视化",
            "position": {
                "x": 49840,
                "y": 50260
            },
            "level": 3,
            "branch": 0,
            "properties": {
                "attrs": {
                    "color": {
                        "type": "string",
                        "description": "颜色",
                        "required": true,
                        "default": "#00FF00",
                        "name": "颜色"
                    },
                    "line_width": {
                        "type": "number",
                        "description": "线宽",
                        "required": true,
                        "default": 2,
                        "name": "线宽"
                    }
                },
                "input_params": {
                    "predictions": {
                        "type": "object",
                        "description": "推理结果",
                        "required": true,
                        "name": "推理结果"
                    },
                    "image": {
                        "type": "image",
                        "description": "图片",
                        "required": true,
                        "name": "图片"
                    }
                },
                "output_params": {
                    "image": {
                        "type": "image",
                        "description": "可视化结果",
                        "required": true,
                        "name": "可视化结果"
                    }
                }
            },
            "iconType": "visualize"
        },
        {
            "id": "52644f3c-6057-4450-8a1a-6737b477d365",
            "type": "semantic_segmentation",
            "title": "语义分割_1",
            "subtitle": "语义分割",
            "position": {
                "x": 49840,
                "y": 50410
            },
            "level": 4,
            "branch": 0,
            "properties": {
                "attrs": {
                    "model_id": {
                        "type": "string",
                        "description": "模型ID",
                        "required": true,
                        "name": "模型ID"
                    }
                },
                "input_params": {
                    "image": {
                        "type": "image",
                        "description": "图片",
                        "required": true,
                        "name": "图片"
                    }
                },
                "output_params": {
                    "predictions": {
                        "type": "object",
                        "description": "分割结果",
                        "required": true,
                        "name": "预测结果"
                    }
                }
            },
            "iconType": "semantic_segmentation"
        }
    ],
    "connections": [
        {
            "id": "input-conn",
            "from": "input",
            "to": "aee0e753-3643-452a-9fb5-9d2dda953244"
        },
        {
            "id": "19b53f7e-6093-4fb5-ba85-93a792b65cfc",
            "from": "aee0e753-3643-452a-9fb5-9d2dda953244",
            "to": "50865899-f9dd-4417-973d-2ccce4c994ef"
        },
        {
            "id": "6484a860-c0ed-4958-b0ac-9e8d1fc91072",
            "from": "8ca5e332-3889-40bc-9991-c68ded5af390",
            "to": "output"
        },
        {
            "id": "be0df973-193f-460b-9b7d-1bcecb49f68c",
            "from": "50865899-f9dd-4417-973d-2ccce4c994ef",
            "to": "32fda8fa-cdea-48aa-bb4e-ee578a0f5bd5"
        },
        {
            "id": "f7e1e6a2-fbc4-4776-bf8f-7b55020e16be",
            "from": "32fda8fa-cdea-48aa-bb4e-ee578a0f5bd5",
            "to": "f65b6774-ebeb-4d62-bb52-ca0f2aa69636"
        },
        {
            "id": "4732cd83-702b-4973-8ef0-1aa90d2c3113",
            "from": "f65b6774-ebeb-4d62-bb52-ca0f2aa69636",
            "to": "52644f3c-6057-4450-8a1a-6737b477d365"
        },
        {
            "id": "8cf75af7-9114-454b-9cac-c8a4a2637420",
            "from": "52644f3c-6057-4450-8a1a-6737b477d365",
            "to": "8ca5e332-3889-40bc-9991-c68ded5af390"
        }
    ]
}
// 原始数据


// 将 nodes 转换为以 id 为键的 Map,便于快速查找
const nodesMap = new Map(data.nodes.map(node => [node.id, node]));

/**
 * 递归查找指定节点的上游节点(满足 output_params 包含目标属性)
 * @param {string} currentNodeId 当前节点 ID(初始为目标节点 ID)
 * @param {string} targetParam 需要检查的 output_params 属性名(如 'image' 或 'predictions')
 * @param {Set} visited 已访问的节点 ID 集合(防止循环)
 * @param {Array} result 结果数组(存储符合条件的上游节点)
 * @returns {Array} 所有符合条件的上游节点
 */
function findUpstreamNodesByOutputParam(
    currentNodeId,
    targetParam,
    visited = new Set(),
    result = []
) {
    // 1. 找到当前节点的所有上游连接(即 connections 中 to === currentNodeId 的记录)
    const incomingConnections = data.connections.filter(conn => conn.to === currentNodeId);

    // 2. 遍历所有上游连接,处理每个上游节点
    for (const conn of incomingConnections) {
        const fromNodeId = conn.from; // 上游节点 ID

        // 3. 跳过输入源(from 为 "input" 的情况)
        if (fromNodeId === 'input') continue;

        // 4. 检查上游节点是否存在(避免无效节点)
        if (!nodesMap.has(fromNodeId)) continue;

        const fromNode = nodesMap.get(fromNodeId); // 获取上游节点对象

        // 5. 避免重复处理(循环引用防护)
        if (visited.has(fromNodeId)) continue;
        visited.add(fromNodeId); // 标记为已访问

        // 6. 检查上游节点的 output_params 是否包含目标属性
        if (fromNode.properties?.output_params?.[targetParam]) {
            result.push(fromNode); // 符合条件则加入结果
        }

        // 7. 递归查找该上游节点的上游节点(继续向上遍历)
        findUpstreamNodesByOutputParam(fromNodeId, targetParam, visited, result);
    }

    return result;
}

// --------------------------
// 使用示例:查找两种类型的节点
// --------------------------

// 目标节点 ID(示例中的可视化节点)
const targetNodeId = '8ca5e332-3889-40bc-9991-c68ded5af390';

// 查找 output_params 包含 "predictions" 的上游节点(如语义分割、语义分割_1)
const predictionsUpstreamNodes = findUpstreamNodesByOutputParam(
    targetNodeId,
    'predictions'
);

// 查找 output_params 包含 "image" 的上游节点(如图片裁剪、图片裁剪_1、推理结果可视化_1)
const imageUpstreamNodes = findUpstreamNodesByOutputParam(
    targetNodeId,
    'image'
);

console.log('找到 predictions 上游节点:', predictionsUpstreamNodes);
console.log('找到 image 上游节点:', imageUpstreamNodes);
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容