如何将扁平JSON转换为带subNav层级结构?现有代码存在嵌套问题
扁平JSON数组转层级化导航结构的实现方案
需求说明
我有一个扁平结构的JSON数组:
const content = [ { title: "Item 1", metaData: { "level": 1, "desc": "Some Desc 1", "displayOnOverview": true }}, { title: "Item 2", metaData: { "level": 2, "desc": "Some Desc 2", "displayOnOverview": true }}, { title: "Item 3", metaData: { "level": 2, "desc": "Some Desc 3", "displayOnOverview": false }}, { title: "Item 4", metaData: { "level": 3, "desc": "Some Desc 4", "displayOnOverview": true }}, { title: "Item 5", metaData: { "level": 1, "desc": "Some Desc 5", "displayOnOverview": true }} ];
需要将其转换为带subNav子层级的嵌套结构:
[ { "title": "Item 1", "metaData": { "desc": "Some Desc 1", "displayOnOverview": true }, "subNav": [ { "title": "Item 2", "metaData": { "desc": "Some Desc 2", "displayOnOverview": true } }, { "title": "Item 3", "metaData": { "desc": "Some Desc 3", "displayOnOverview": false }, "subNav": [ { "title": "Item 4", "metaData": { "desc": "Some Desc 4", "displayOnOverview": true } } ] } ] }, { "title": "Item 5", "metaData": { "desc": "Some Desc 5", "displayOnOverview": true } } ]
现有代码的问题
我写的代码只能处理顶层节点,遇到Item 3这类同级节点时就失效了:
// Create root for top-level node(s) const root = []; sideNavData.forEach((node, index) => { const nodeLevel = node.metaData.level; if (root.length === 0) { return root.push(node) } const previousLevel = root[index - 1].metaData.level; if (previousLevel === nodeLevel) { return root.push(node) } else { return root[index - 1]['subNav'] = node } }); console.log(root);
核心问题:
- 仅跟踪根数组的前一个元素,未考虑深层嵌套的父节点
- 直接将子节点赋值为单个对象,而非数组,无法支持多个同级子节点
- 未处理层级跨级跳转的场景(比如从level3回到level1)
实现思路
解决这类层级转换问题的核心是维护一个层级栈,通过栈记录当前各层级的父节点,快速定位当前节点的归属:
- 初始化根结果数组和层级栈,栈中每个元素保存节点实例及其对应的层级
- 遍历每个扁平节点:
- 复制当前节点并移除
metaData中的level字段(目标结构不需要该字段) - 根据当前节点的层级,调整栈的长度:弹出栈中所有层级大于等于当前层级的元素,直到找到层级比当前小1的父节点
- 若当前层级为1,直接加入根数组并推入栈;若为子节点,找到栈顶父节点,确保
subNav数组存在后将当前节点加入,再推入栈
- 复制当前节点并移除
完整实现代码
const content = [ { title: "Item 1", metaData: { "level": 1, "desc": "Some Desc 1", "displayOnOverview": true }}, { title: "Item 2", metaData: { "level": 2, "desc": "Some Desc 2", "displayOnOverview": true }}, { title: "Item 3", metaData: { "level": 2, "desc": "Some Desc 3", "displayOnOverview": false }}, { title: "Item 4", metaData: { "level": 3, "desc": "Some Desc 4", "displayOnOverview": true }}, { title: "Item 5", metaData: { "level": 1, "desc": "Some Desc 5", "displayOnOverview": true }} ]; function flattenToNested(data) { const result = []; const stack = []; data.forEach(item => { // 复制节点并移除metaData中的level字段 const node = { title: item.title, metaData: { ...item.metaData } }; delete node.metaData.level; const currentLevel = item.metaData.level; // 调整栈:弹出所有层级 >= 当前层级的节点,找到父节点 while (stack.length > 0 && stack[stack.length - 1].level >= currentLevel) { stack.pop(); } if (currentLevel === 1) { result.push(node); } else { // 获取父节点,确保subNav存在 const parent = stack[stack.length - 1].node; if (!parent.subNav) { parent.subNav = []; } parent.subNav.push(node); } // 将当前节点和层级推入栈 stack.push({ node, level: currentLevel }); }); return result; } const nestedNav = flattenToNested(content); console.log(JSON.stringify(nestedNav, null, 2));
内容的提问来源于stack exchange,提问作者ReynierPM
相关产品推荐
相关产品推荐

