You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现无限嵌套对象数组中选中行及其所有子项的删除?

问题:删除选中行及其所有层级子项(修复递归栈溢出)

数据结构与需求

我们有如下扁平化的树形数据结构,需要实现删除选中行及其所有后代子项(包括子项的子项等):

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数组查找对应项,效率低下且容易出错

修复方案

核心改进点

  1. 递归函数直接接收data数组中的真实索引,而非子数组索引
  2. 使用Set存储待删除索引,自动去重,避免重复添加
  3. 直接通过索引从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 15:30:53