js写的递归总是获取不到数据?

不知道这个递归是哪块出了问题,这个方法总是获取空数组?

const findOperate = (arr = [], menuName) => {
  let res = []
  for (let i = 0; i < arr.length; i++) {
    if (arr[i].name === menuName) {
      res = arr[i].operation_list
      break
    } else {
      if (arr[i].menu_list.length) {
        findOperate(arr[i].menu_list, menuName)
      }
    }
  }
  return res
}

findOperate(arr, '系统管理员')
const arr = [
    {
        "id": "169880657983438848",
        "code": "systemConfig",
        "name": "系统配置管理",
        "route": "/systemConfig",
        "description": "系统配置管理",
        "menu_list": [],
        "operation_list": [
            {
                "id": "170594677588754432",
                "code": "add",
                "name": "新增",
                "description": ""
            },
            {
                "id": "170594694908084224",
                "code": "edit",
                "name": "编辑",
                "description": ""
            },
            {
                "id": "170594706926862336",
                "code": "delete",
                "name": "删除",
                "description": ""
            }
        ]
    },
    {
        "id": "169880805688999936",
        "code": "userManage",
        "name": "系统用户管理",
        "route": "",
        "description": "系统用户管理菜单",
        "menu_list": [
            {
                "id": "169880863841976320",
                "code": "adminManage",
                "name": "系统管理员",
                "route": "/adminManage",
                "description": "系统管理员菜单",
                "menu_list": [],
                "operation_list": [
                    {
                        "id": "170594813441212416",
                        "code": "add",
                        "name": "新增",
                        "description": ""
                    },
                    {
                        "id": "170594834417975296",
                        "code": "edit",
                        "name": "编辑",
                        "description": ""
                    },
                    {
                        "id": "170594849289928704",
                        "code": "disable",
                        "name": "停用",
                        "description": ""
                    },
                    {
                        "id": "170595468132220928",
                        "code": "resetPassword",
                        "name": "重置密码",
                        "description": ""
                    },
                    {
                        "id": "170801863500759040",
                        "code": "enable",
                        "name": "启用",
                        "description": ""
                    }
                ]
            },
            {
                "id": "169880911479832576",
                "code": "masterManage",
                "name": "专家",
                "route": "/masterManage",
                "description": "专家菜单",
                "menu_list": [],
                "operation_list": [
                    {
                        "id": "170594872555732992",
                        "code": "add",
                        "name": "新增",
                        "description": ""
                    },
                    {
                        "id": "170594885485723648",
                        "code": "edit",
                        "name": "编辑",
                        "description": ""
                    },
                    {
                        "id": "170594898276253696",
                        "code": "disable",
                        "name": "停用",
                        "description": ""
                    },
                    {
                        "id": "170595499383980032",
                        "code": "resetPassword",
                        "name": "重置密码",
                        "description": ""
                    },
                    {
                        "id": "170801897956966400",
                        "code": "enable",
                        "name": "启用",
                        "description": ""
                    }
                ]
            },
            {
                "id": "169880942211497984",
                "code": "personManage",
                "name": "学员",
                "route": "/personManage",
                "description": "学员菜单",
                "menu_list": [],
                "operation_list": [
                    {
                        "id": "170594919992262656",
                        "code": "add",
                        "name": "新增",
                        "description": ""
                    },
                    {
                        "id": "170594932861435904",
                        "code": "edit",
                        "name": "编辑",
                        "description": ""
                    },
                    {
                        "id": "170594945705443328",
                        "code": "disable",
                        "name": "停用",
                        "description": ""
                    },
                    {
                        "id": "170595520110133248",
                        "code": "resetPassword",
                        "name": "重置密码",
                        "description": ""
                    },
                    {
                        "id": "170801931430658048",
                        "code": "enable",
                        "name": "启用",
                        "description": ""
                    }
                ]
            }
        ],
        "operation_list": []
    },
    {
        "id": "169881001833529344",
        "code": "projectTrain",
        "name": "项目培训管理",
        "route": "",
        "description": "项目培训管理菜单",
        "menu_list": [
            {
                "id": "169881081221218304",
                "code": "projectManage",
                "name": "项目管理",
                "route": "/projectManage",
                "description": "项目管理菜单",
                "menu_list": [],
                "operation_list": [
                    {
                        "id": "170594987126292480",
                        "code": "add",
                        "name": "新增",
                        "description": ""
                    },
                    {
                        "id": "170595004892315648",
                        "code": "edit",
                        "name": "编辑",
                        "description": ""
                    },
                    {
                        "id": "170595020011732992",
                        "code": "delete",
                        "name": "删除",
                        "description": ""
                    },
                    {
                        "id": "170595099047100416",
                        "code": "trainImport",
                        "name": "批量导入培训",
                        "description": ""
                    }
                ]
            },
            {
                "id": "169881144667406336",
                "code": "trainManage",
                "name": "培训管理",
                "route": "/trainManage",
                "description": "培训管理菜单",
                "menu_list": [],
                "operation_list": [
                    {
                        "id": "170595119011987456",
                        "code": "add",
                        "name": "新增",
                        "description": ""
                    },
                    {
                        "id": "170595131858092032",
                        "code": "edit",
                        "name": "编辑",
                        "description": ""
                    },
                    {
                        "id": "170595142873382912",
                        "code": "delete",
                        "name": "删除",
                        "description": ""
                    },
                    {
                        "id": "170595163668742144",
                        "code": "trainCourse",
                        "name": "课程列表",
                        "description": ""
                    },
                    {
                        "id": "170595186249826304",
                        "code": "trainPerson",
                        "name": "学员列表",
                        "description": ""
                    }
                ]
            },
            {
                "id": "169881182098423808",
                "code": "courseManage",
                "name": "课程库",
                "route": "/courseManage",
                "description": "课程库菜单",
                "menu_list": [],
                "operation_list": [
                    {
                        "id": "170595312643080192",
                        "code": "add",
                        "name": "新增",
                        "description": ""
                    },
                    {
                        "id": "170595323860746240",
                        "code": "edit",
                        "name": "编辑",
                        "description": ""
                    },
                    {
                        "id": "170595335360479232",
                        "code": "delete",
                        "name": "删除",
                        "description": ""
                    }
                ]
            }
        ],
        "operation_list": []
    },
    {
        "id": "169881236203896832",
        "code": "dataAnalysis",
        "name": "项目培训统计",
        "route": "",
        "description": "项目培训统计菜单",
        "menu_list": [
            {
                "id": "169881284272717824",
                "code": "projectAnalysis",
                "name": "项目统计",
                "route": "/projectAnalysis",
                "description": "项目统计菜单",
                "menu_list": [],
                "operation_list": [
                    {
                        "id": "170595379336708096",
                        "code": "export",
                        "name": "导出",
                        "description": ""
                    }
                ]
            },
            {
                "id": "169881324465684480",
                "code": "trainAnalysis",
                "name": "培训统计",
                "route": "/trainAnalysis",
                "description": "培训统计菜单",
                "menu_list": [],
                "operation_list": [
                    {
                        "id": "170595397435129856",
                        "code": "export",
                        "name": "导出",
                        "description": ""
                    }
                ]
            },
            {
                "id": "169881363680329728",
                "code": "personAnalysis",
                "name": "学员统计",
                "route": "/personAnalysis",
                "description": "学员统计菜单",
                "menu_list": [],
                "operation_list": [
                    {
                        "id": "170595413102952448",
                        "code": "export",
                        "name": "导出",
                        "description": ""
                    }
                ]
            }
        ],
        "operation_list": []
    }
]
阅读 2.1k
3 个回答
    const findOperate = (arr = [], menuName) => {
        let res = undefined
        for (let i = 0; i < arr.length; i++) {
          if (arr[i].name === menuName) {
            res = arr[i].operation_list
            break;
          } else {
            if (arr[i].menu_list.length) {
              res = findOperate(arr[i].menu_list, menuName)
              if(res) {
                break;
              }
            }
          }
        }
        return res
      }
这是chatGpt给的答案

这个递归方法有问题的地方是在没有把递归函数的返回值加入到 res 数组中。当你递归调用 findOperate() 函数时,你并没有对其返回值进行任何操作,导致最终 res 数组的值为初始值空数组 []。

要解决这个问题,你需要在调用 findOperate() 函数时将其返回值合并到 res 数组中。你可以使用 Array.prototype.concat() 方法来将两个数组合并:

if (arr[i].menu_list.length) {
  res = res.concat(findOperate(arr[i].menu_list, menuName))
}

这样做可以将递归调用的返回值合并到 res 数组中,从而保证最终返回的结果包含所有匹配的操作列表。

以下是修改后的代码:

const findOperate = (arr = [], menuName) => {
  let res = []
  for (let i = 0; i < arr.length; i++) {
    if (arr[i].name === menuName) {
      res = arr[i].operation_list
      break
    } else {
      if (arr[i].menu_list.length) {
        res = res.concat(findOperate(arr[i].menu_list, menuName))
      }
    }
  }
  return res
}

现在你应该能够得到正确的结果了

ChatGPT 还是强悍,居然一下子就找到了问题。下面是我的人工解答。
/**
 * 
 * @param {any[]} arr 搜索范围
 * @param {string} menuName 搜索目标
 * @returns 
 */
const findOperate = (arr = [], menuName) => {
    let res = [];
    for (let i = 0; i < arr.length; i++) {
        if (arr[i].name === menuName) {
            // 这里找到了结果,可以直接 return arr[i].operation_list,
            // 因为后面没有对 res 进行再处理
            // 可直接返回代替「暂存→break→return」这个过程
            res = arr[i].operation_list;
            break;
        } else {
            if (arr[i].menu_list.length) {
                // 问题在这里:递归调用的返回值没有处理
                // findOperate(arr[i].menu_list, menuName);
                // 应该判断,如果找到了就返回,否则继续循环,所以
                res = findOperate(arr[i].menu_list, menuName);
                if (res?.length) { return res; }
            }
        }
    }
    return res;
};

以下是优化过的代码:

const findOperate = (arr = [], menuName) => {
    for (let it of arr) {
        if (it.name === menuName) { return it.operation_list; }
        if (it.menu_list?.length) {
            const res = findOperate(it.menu_list, menuName);
            if (res) { return res; }
        }
    }
};

const result = findOperate(arr, "系统管理员") ?? [];

算法是一样的,只在处理了这些:

  • res 不需要事先定义,如果没找到直接返回 undefined(默认返回),只不过这样在没有匹配项的时候 findOperate 会得到 undefined,根据实际需求看要不要处理成 []
  • 另外,这个逻辑和原来的逻辑还有一点不同,就是找到节点的 operation_list 是空的 ([]) 也算找到。原来的逻辑找到空列表会继续找。
  • 去掉了不必要的 break。既然 break 出去就是 return,那可以直接 return
  • for(i) 循环改为了 foreach 循环,减少 arr[i],这东西多了看起来容易晕。就算用 for(i),一般也会在循环体刚开始的时候用一个临时变量,比如 const it = arr[i]
  • AI 说的把所有结果连接起来,我个人认为没必要,因为从逻辑上判断,要查找的节点应该只有一个,要不然也不会 break 了。如果存在多个目标节点,可以参阅下面的文章链接。另外,concat 连接中规中矩,可以用 res.push(...findOperate(...))

另外,建议阅读:

推荐问题
宣传栏