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

TypeScript递归删除数组指定条件组问题求助

树形条件组递归删除失效问题排查与修复

问题背景

需要实现树形结构条件组的删除功能:点击X按钮删除指定的整个分组,但现有递归删除代码无法完成删除操作,尽管执行时能读取到待修改的conditions数组。

数据结构

对应的TypeScript对象结构如下:

{
  nodeName: 'and',
  nodeID: 1,
  parentNodeID: null,
  conditions: [
    {
      children: [],
      displayDataField: 'Cliente.Centro.Centro',
      order: 1,
      value1: '1',
      parentNodeID: 1,
    },
    {
      order: 2,
      dataField: null,
      condition: null,
      value: null,
      parentNodeID: 1,
      children: [
        {
          nodeName: 'or',
          nodeID: 2,
          parentNodeID: 1,
          conditions: [
            {
              children: [],
              displayDataField: 'Cliente.Datos.Código cliente',
              order: 1,
              value1: '333',
              parentNodeID: 2,
            },
            {
              children: [],
              displayDataField: 'Cliente.Datos.Código cliente',
              order: 2,
              value1: '44',
              parentNodeID: 2,
            },
            {
              order: 3,
              dataField: null,
              condition: null,
              value: null,
              parentNodeID: 2,
              children: [
                {
                  nodeName: 'or',
                  nodeID: 3,
                  parentNodeID: 2,
                  conditions: [
                    {
                      children: [],
                      displayDataField: 'Cliente.Datos.Código cliente',
                      order: 1,
                      value1: '1',
                      parentNodeID: 3,
                    },
                    {
                      children: [],
                      displayDataField: 'Cliente.Datos.Código cliente',
                      order: 2,
                      value1: '30000',
                      parentNodeID: 3,
                    },
                  ],
                },
              ],
            },
          ],
        },
      ],
    },
    {
      children: [],
      displayDataField: 'Cliente.Datos.Fecha de nacimiento',
      order: 3,
      value1: '01/02/1980',
      parentNodeID: 1,
    },
  ],
};

现有代码

当前编写的删除逻辑代码:

onDeleteConditionGroup(eventInfo: { e: any; condition: QueryConditionDto }) {
  this.queryGroupService.deleteConditionGroup(this.globalQuery.query.conditions, eventInfo.condition.parentNodeID);
}

deleteConditionGroup(query: QueryConditionDto[], nodeID: number) {
  this._found = false;
  this._queryModified = [];
  this._deleteConditionGroup(query, nodeID);
}

private _deleteConditionGroup(query: QueryConditionDto[], nodeID: number, found: boolean = false) {
  query.forEach((item: QueryConditionDto) => {
    if (!found) {
      if (this.queryService.isGroupCondition(item) && item.children[0].nodeID == nodeID) {
        const index = query.findIndex((condition: QueryConditionDto) => condition.children[0]?.nodeID == nodeID);

        // We must choose the preconditions and postconditions
        // The conditions that follow must update their order attribute.
        if (index > -1) {
          const conditionsPrevious = query.filter((condition: QueryConditionDto) => condition.order < query[index].order);
          const conditionsBack = query.filter((condition: QueryConditionDto) => condition.order > query[index].order);

          conditionsBack.forEach((condition: QueryConditionDto) => {
            condition.order = condition.order - 1;
          });

          // We keep the conditions except for the deleted one. BUT IT DOESN'T WORK IT DOESN'T REMOVE ME WTF?!?
          query = conditionsPrevious.concat(conditionsBack);

          this._found = true;
        }
      }
      else if (this.queryService.isGroupCondition(item) && item.children[0].nodeID != nodeID && !this._found) {
        this._deleteConditionGroup(item.children[0].conditions, nodeID);
      }
    }
  });
}

问题分析

  1. 数组引用未修改:query = conditionsPrevious.concat(conditionsBack)只是给局部变量query重新赋值,并没有修改传入的原数组的内容,原数组完全没变化,这是删除失效的核心原因。
  2. 遍历逻辑缺陷:使用forEach循环时,即使找到目标并标记_found = true,循环仍会继续执行;同时依赖全局变量_found控制递归,容易出现状态不一致的问题。
  3. 目标定位逻辑问题:判断条件item.children[0].nodeID == nodeID不够严谨,且递归进入子节点时的逻辑没有覆盖所有可能的嵌套场景。

修复方案

修改后的递归删除代码如下,核心改动点已标注:

onDeleteConditionGroup(eventInfo: { e: any; condition: QueryConditionDto }) {
  this.queryGroupService.deleteConditionGroup(this.globalQuery.query.conditions, eventInfo.condition.parentNodeID);
}

deleteConditionGroup(query: QueryConditionDto[], nodeID: number) {
  // 直接调用递归函数,用返回值判断是否找到并删除
  this._deleteConditionGroup(query, nodeID);
}

private _deleteConditionGroup(query: QueryConditionDto[], nodeID: number): boolean {
  // 使用for循环,方便找到目标后立即终止遍历
  for (let i = 0; i < query.length; i++) {
    const item = query[i];
    
    if (this.queryService.isGroupCondition(item)) {
      // 先检查当前item是否是要删除的组的容器
      if (item.children[0]?.nodeID === nodeID) {
        // 1. 直接用splice修改原数组,删除目标项
        query.splice(i, 1);
        
        // 2. 更新后续项的order值
        for (let j = i; j < query.length; j++) {
          query[j].order -= 1;
        }
        
        // 返回true表示已找到并删除
        return true;
      }
      
      // 递归进入子条件组,检查是否在子节点中找到目标
      const foundInChild = this._deleteConditionGroup(item.children[0].conditions, nodeID);
      if (foundInChild) {
        return true;
      }
    }
  }
  
  // 未找到目标,返回false
  return false;
}

关键改动说明

  • 直接修改原数组:使用array.splice()方法直接操作传入的数组,确保原数组的内容被修改,解决了之前局部变量赋值无效的问题。
  • 递归返回值控制:递归函数返回布尔值,标记是否找到并删除了目标,避免依赖全局变量,逻辑更清晰可靠。
  • for循环替代forEach:使用for循环可以在找到目标后立即终止遍历,提升效率,同时避免forEach循环中修改数组导致的遍历异常。
  • 简化order更新逻辑:删除目标项后,直接遍历后续的项更新order,比之前的filter+concat更高效且直观。

内容的提问来源于stack exchange,提问作者Stella Esparza

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 19:10:48