JavaScript数据结构反转与去重求助:多层Topic嵌套转换
问题:嵌套Topic数据结构的层级反转与去重
输入数据结构
const data = [ { "id": 1, "attributes": { "name": "Mother of All Topics", "info": "Notice", "parentTopic": { "data": null } } }, // 其余数据省略 ];
现有尝试的递归函数
// 生成前缀 const getPrefix = (prefix, i) => prefix ? `${prefix}.${i + 1}` : `${i + 1}`; // 反转层级 const invertHierarchy = (arr, parentTopic, prefix) => arr .filter((e) => e.parentTopic.data?.id === parentTopic) .map((e, i) => ({ ...e, index: getPrefix(prefix, i), topics: invertHierarchy(arr, e.id, getPrefix(prefix, i)), }));
该函数仅支持一层嵌套,无法处理多层嵌套场景,也未覆盖输入中嵌套父节点的收集与节点去重需求。
目标输出结构
[ { "id": 1, "name": "Mother of All Topics", "topics": [ { "id": 2, "name": "Important Topic", "info": null, "topics": [ { "id": 3, "name": "Critical Topic", "topics": [] } ] } ] }, // 其余结构省略 ]
更新后的输入输出示例
更新输入
const updatedData = [ { "id": 25, "attributes": { "name": "Nice Topic", "info": "", "parentTopic": { "data": { "id": 24, "attributes": { "name": "Critical Top Level", "info": "", "parentTopic": { "data": null } } } } } }, // 其余数据省略 ];
期望输出
[ { "id": 24, "name": "Critical Top Level", "info": "", "topics": [ { "id": 25, "name": "Nice Topic", "info": "", "topics": [] } ] }, // 其余结构省略 ]
核心需求
- 将含嵌套父节点的扁平Topic数据转换为层级结构,父节点位于顶层,子节点嵌套在
topics数组中 - 自动收集所有嵌套的父节点,避免丢失
- 基于
id对节点去重 - 支持任意层级的嵌套
解决方案
实现思路
- 扁平化收集所有节点:遍历输入数据,递归收集嵌套在
parentTopic.data中的所有节点,用Map存储以实现去重 - 构建父子关系映射:遍历所有节点,记录每个节点的子节点列表
- 递归生成层级结构:从顶层节点(
parentTopic.data为null)开始,递归转换每个节点为目标格式
代码实现
// 扁平化收集所有节点(含嵌套父节点)并去重 const collectAllNodes = (items, nodeMap = new Map()) => { items.forEach(item => { if (!nodeMap.has(item.id)) { nodeMap.set(item.id, item); } const parentData = item.attributes.parentTopic.data; if (parentData) { collectAllNodes([parentData], nodeMap); } }); return Array.from(nodeMap.values()); }; // 构建层级结构 const buildHierarchy = (nodes) => { const nodeMap = new Map(); const childrenMap = new Map(); nodes.forEach(node => { nodeMap.set(node.id, node); if (!childrenMap.has(node.id)) { childrenMap.set(node.id, []); } const parentId = node.attributes.parentTopic.data?.id; if (parentId !== undefined) { if (!childrenMap.has(parentId)) { childrenMap.set(parentId, []); } childrenMap.get(parentId).push(node); } }); const buildNode = (node) => { const { id, attributes: { name, info } } = node; return { id, name, info: info ?? null, topics: (childrenMap.get(id) || []).map(child => buildNode(child)) }; }; return nodes .filter(node => node.attributes.parentTopic.data === null) .map(node => buildNode(node)); }; // 主函数:整合流程 const invertTopicHierarchy = (inputData) => { const allNodes = collectAllNodes(inputData); return buildHierarchy(allNodes); }; // 使用示例 const result = invertTopicHierarchy(updatedData); console.log(JSON.stringify(result, null, 2));
代码说明
collectAllNodes:递归遍历输入,收集所有节点并通过Map确保每个id唯一buildHierarchy:- 先构建节点映射和父子关系映射,提升查找效率
buildNode递归转换节点结构,自动处理子节点嵌套- 筛选顶层节点生成最终层级结构
- 自动处理
info为空的情况,转换为null匹配目标输出格式
内容的提问来源于stack exchange,提问作者JimminyCricket
相关产品推荐
相关产品推荐

