树形结构数据查找某个 key 的路径

需求

假设有一个树形数据treeData

javascript 复制代码
const treeData = [
    { key: 1, title: 'node1'},
    { key: 2, title: 'node2', children: 
        [
            { key: 3, title: 'node3', children: 
                [
                    { key: 4, title: 'node4' }
                ]
            }
         ]
     }
]

大概就是这么个数据,现在给出一个 key,可以得到该节点的路径。

例如给出的 key 为4,那么期望得到 [1, 'children', 0, 'children', 0],奇数部分代表 children 中的 index,偶数部分固定是 'children',可以看到得到这个 path 数组后可以直接拿到这个节点的数据,比如使用 lodash 中的 get 方法,或者循环 path 取值。

思路

直接看一下完整代码

javascript 复制代码
function findKeyPath(treelikeData, targetKey, childrenKey = 'children') {
  const recursiveSearch = (_treelikeData = []) => {
    let path = [];
    const hasKey = _treelikeData.some((dataItem, index) => {
      if (dataItem.key === targetKey) {
        path.push(index);
        return true;
      }
      if (Array.isArray(dataItem[childrenKey])) {
        const searchResult = recursiveSearch(dataItem[childrenKey]);
        if (searchResult.hasKey) {
          path = [...path, index, childrenKey, ...searchResult.path];
        }
        return searchResult.hasKey;
      }
      return false;
    });
    return { hasKey, path };
  };

  const searchResult = recursiveSearch(treelikeData);
  return searchResult.path;
}

我的思路是这样的,先写一个递归的搜索函数recursiveSearch,这个函数会返回hasKey 和 path 两个数据,path 是最终要得到的路径,hasKey是用来判断是否找到了 key。

用Array 的 some 函数来遍历数据的原因是,当返回了 true 之后,遍历会立即停止,这样能节省些开销,且 some 的返回结果就是 true 或 false,正好可以用来判断是否找到了。

在查找判断是否有 key 时,先排除 2 种边界情况:

  1. 如果dataItem.key === targetKey,就直接返回 true 并且把该数据的 index 添加进 path 中,这是已经递归到最末端的情况了。
  2. 排除 1 情况后,遍历出来的当前item,没有子数组了,说明这一枝并没有要寻找的数据,直接返回 false

接下来就是需要递归的部分了,此时复杂的情况已经简化了,首先递归查找当前数据的子数组中是否有要查找的数据,就像上面说的那样,递归搜索函数的返回结果是path和 hasKey,这时候判断一下hasKey是true还是false,如果是true的话,就将子数组返回的path和当前的path合并(中间加上当前的index和 'children')

使用

javascript 复制代码
const keyPath = findKeyPath(treeData, '4')
//  [1, 'children',  0, 'children',  0]

ps: 其实如果数据是后端传来的,可能返回的是 [{ id: 1, children: [] }] 这样的数据,这部分取值时修改成 dataItem.key,或者定义一个参数 dataItem[keyName]即可

相关推荐
qq_177767372 小时前
React Native鸿蒙跨平台数据使用监控应用技术,通过setInterval每5秒更新一次数据使用情况和套餐使用情况,模拟了真实应用中的数据监控场景
开发语言·前端·javascript·react native·react.js·ecmascript·harmonyos
烬头88212 小时前
React Native鸿蒙跨平台应用实现了onCategoryPress等核心函数,用于处理用户交互和状态更新,通过计算已支出和剩余预算
前端·javascript·react native·react.js·ecmascript·交互·harmonyos
程序员清洒3 小时前
Flutter for OpenHarmony:Text — 文本显示与样式控制
开发语言·javascript·flutter
雨季6664 小时前
Flutter 三端应用实战:OpenHarmony 简易“动态内边距调节器”交互模式深度解析
javascript·flutter·ui·交互·dart
天人合一peng4 小时前
Unity中button 和toggle监听事件函数有无参数
前端·unity·游戏引擎
会飞的战斗鸡4 小时前
JS中的链表(含leetcode例题)
javascript·leetcode·链表
方也_arkling5 小时前
别名路径联想提示。@/统一文件路径的配置
前端·javascript
毕设源码-朱学姐5 小时前
【开题答辩全过程】以 基于web教师继续教育系统的设计与实现为例,包含答辩的问题和答案
前端
qq_177767375 小时前
React Native鸿蒙跨平台剧集管理应用实现,包含主应用组件、剧集列表、分类筛选、搜索排序等功能模块
javascript·react native·react.js·交互·harmonyos
qq_177767375 小时前
React Native鸿蒙跨平台自定义复选框组件,通过样式数组实现选中/未选中状态的样式切换,使用链式调用替代样式数组,实现状态驱动的样式变化
javascript·react native·react.js·架构·ecmascript·harmonyos·媒体