如何实现无限嵌套对象数组中选中行及其所有子项的删除?
问题:删除选中行及其所有层级子项(修复递归栈溢出)
数据结构与需求
我们有如下扁平化的树形数据结构,需要实现删除选中行及其所有后代子项(包括子项的子项等):
interface DataType { level: number; type: string | number | string[] | number[] | object[] | object; key: string; value: any; children: number[] // 存储子项在data数组中的索引 } const data = [ { level: 1, type: 'obj', key: 'obj1', value: {}, children: [1, 2] }, { level: 2, type: 'string', key: 'obj1 child', value: 'child string', children: [] }, { level: 2, type: 'obj', key: 'obj1 child obj', value: {}, children: [3] }, { level: 3, type: 'obj', key: 'obj1-1', value: {}, children: [4] }, { level: 4, type: 'obj', key: 'obj1-1-1', value: {}, children: [5] }, { level: 5, type: 'string', key: 'obj1-1-1-1', value: 'last nest', children: [] }, ]
现有代码问题
尝试递归实现时出现栈溢出,核心错误是:
- 递归调用时传入了子项在children数组中的索引(
index3),而非子项在data数组中的真实索引(item3) - 每次递归都遍历整个
data数组查找对应项,效率低下且容易出错
修复方案
核心改进点
- 递归函数直接接收
data数组中的真实索引,而非子数组索引 - 使用
Set存储待删除索引,自动去重,避免重复添加 - 直接通过索引从
data中获取当前项,无需遍历整个数组
修复后的完整代码
// 假设当前处于data数组的.map遍历中,能获取到item和index <button onClick={(): void => { const index2Delete = new Set<number>(); // 递归收集所有待删除的索引 const collectDeleteIndexes = (targetIndex: number) => { // 添加当前索引到待删除集合 index2Delete.add(targetIndex); const currentItem = data[targetIndex]; // 递归处理所有子项 currentItem.children.forEach(childIndex => { collectDeleteIndexes(childIndex); }); }; // 启动递归,收集选中项及其所有后代 collectDeleteIndexes(index); // 过滤掉待删除项 const filtered = data.filter((_, idx) => !index2Delete.has(idx)); // 更新数据列表 handleUpdateNewDataList(filtered); }} > Delete </button>
代码解释
Set去重:使用Set存储待删除索引,避免同一索引被多次添加(比如子项被多个父项引用的场景)- 递归逻辑简化:直接通过
targetIndex获取当前项,然后遍历其children中的真实索引,递归调用收集函数 - 无冗余遍历:不再遍历整个
data数组查找项,直接通过索引访问,提升效率 - 避免栈溢出:递归调用的参数是正确的
data数组索引,不会出现无限递归的情况
额外优化(可选)
如果担心递归深度过大导致栈溢出(比如层级极深的树),可以改用迭代方式实现:
<button onClick={(): void => { const index2Delete = new Set<number>(); const stack = [index]; // 使用栈模拟递归 while (stack.length > 0) { const currentIdx = stack.pop()!; index2Delete.add(currentIdx); const currentItem = data[currentIdx]; // 将子项索引推入栈,继续处理 stack.push(...currentItem.children); } const filtered = data.filter((_, idx) => !index2Delete.has(idx)); handleUpdateNewDataList(filtered); }} > Delete </button>
内容的提问来源于stack exchange,提问作者lala
相关产品推荐
相关产品推荐

