如何过滤无限嵌套对象数组?移除指定ID节点及其子节点
移除无限嵌套数组中指定ID节点的最优方案
给定如下无限嵌套的对象数组:
const data = [ { id: 1, children:[ { id: 2, children:[ { id: 3, children:[ { id: 4, children: [], }, { id: 5, children: [], } ], }, ], }, ], }, { id: 8, children:[ { id: 9, children:[ { id: 10, children: [], }, ], }, ], }, ];
需要移除指定ID(比如ID=3)及其所有子节点,返回新数组,处理后结果如下:
const result = [ { id: 1, children:[ { id: 2, children: [], }, ], }, { id: 8, children:[ { id: 9, children:[ { id: 10, children: [], }, ], }, ], }, ];
最优实现方案
直接用递归+reduce的纯函数方案,逻辑清晰且不会修改原数据,代码如下:
function removeNodeById(data, targetId) { return data.reduce((acc, node) => { // 匹配到目标ID,直接跳过该节点 if (node.id === targetId) { return acc; } // 复制当前节点,递归处理子节点数组 const newNode = { ...node, children: removeNodeById(node.children || [], targetId) }; acc.push(newNode); return acc; }, []); } // 使用示例 const processedData = removeNodeById(data, 3);
方案说明
- 纯函数特性:整个过程不会修改原数组和节点,返回全新的数组,避免副作用导致的意外问题
- 递归处理嵌套:天然适配无限嵌套的结构,不管目标节点在第几层,都能精准定位并移除
- 简洁高效:用
reduce遍历数组构建结果,代码简洁,时间复杂度为O(n)(n为所有节点总数) - 鲁棒性:通过
node.children || []处理节点没有children属性的情况,避免报错
极端场景补充
如果你的数据层级极深(超过JS引擎递归栈限制,一般是几万层),可以把递归改成迭代版,用栈来模拟递归过程,示例如下:
function removeNodeByIdIterative(data, targetId) { const stack = [...data]; const result = []; const parentMap = new Map(); // 记录节点的父级数组 // 初始化根节点的父级映射 data.forEach(node => parentMap.set(node, result)); while (stack.length > 0) { const node = stack.pop(); if (node.id === targetId) { // 找到目标节点,从父级数组中移除 const parentArr = parentMap.get(node); const index = parentArr.findIndex(n => n.id === node.id); if (index !== -1) { parentArr.splice(index, 1); } continue; } // 复制节点,处理子节点 const newNode = { ...node, children: [] }; const parentArr = parentMap.get(node); parentArr.push(newNode); // 处理子节点,记录父级映射 if (node.children && node.children.length > 0) { node.children.forEach(child => { parentMap.set(child, newNode.children); stack.push(child); }); } } return result; }
不过绝大多数业务场景下,递归方案已经足够高效且易维护,迭代版仅作为极端情况的补充。
内容的提问来源于stack exchange,提问作者Donny
相关产品推荐
相关产品推荐

