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

JavaScript中如何编写递归函数实现点分隔键转嵌套去重菜单

点分隔键递归生成去重嵌套菜单实现方案

核心问题定位

现有代码仅在一级菜单做了同名键查重,未对深层子节点执行统一的去重逻辑,本质是没有把「同层同名键复用节点」的规则递归应用到所有层级,才会出现project下多个重复type、id子项的问题。

实现思路

  • 所有层级统一遵循「同层同名键仅保留一个节点,后续同路径段共享该节点的子容器」规则
  • 同层节点先用对象结构存储,以路径段名为键,天然实现同层去重,避免遍历数组查重的性能损耗,最后统一转为菜单组件常用的数组格式即可
  • 逐段拆分点分隔的键名,从根节点开始逐层向下遍历,不存在的节点则新建,存在则直接复用进入下一层

完整实现代码

/**
 * 从点分隔的平级键集合生成无重复的嵌套菜单结构
 * @param {string[]} flatKeyList 从res对象中提取的所有点分隔键名数组
 * @returns {Array<{label: string, children: Array}>} 标准嵌套菜单结构
 */
function generateUniqueNestedMenu(flatKeyList) {
  // 初始化根容器,children用对象存储实现按key快速去重
  const root = { children: {} }

  // 遍历所有平级键,逐层挂载节点
  flatKeyList.forEach(fullKey => {
    const pathSegments = fullKey.split('.')
    let currentLevel = root

    pathSegments.forEach(seg => {
      // 当前层级不存在该段名的节点则新建
      if (!currentLevel.children[seg]) {
        currentLevel.children[seg] = {
          label: seg,
          children: {}
        }
      }
      // 指针下移到当前节点,处理下一层路径
      currentLevel = currentLevel.children[seg]
    })
  })

  // 递归将对象格式的children转为数组格式
  function formatToMenuArray(node) {
    return Object.values(node.children).map(item => ({
      ...item,
      // 存在子节点则递归转换,没有则返回空数组
      children: Object.keys(item.children).length ? formatToMenuArray(item) : []
    }))
  }

  return formatToMenuArray(root)
}

// 调用示例:替换为你实际从res取键名的逻辑即可
const resKeys = Object.keys(yourResponseData)
const finalMenuTree = generateUniqueNestedMenu(resKeys)

效果说明

传入包含重复路径段的平级键集合(例如同时存在project.type.id、project.type.name、project.id等多个project前缀的键),最终输出结构中:

  • 一级菜单的user、department、project均仅出现一次
  • project节点下的type、id、name子项无重复
  • type节点下的id、name子项同样自动去重,完全符合嵌套结构预期

内容的提问来源于stack exchange,提问作者su-wan Kenobi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:48:04