首页 > 其他分享 >JS使用递归将原始数据转换为树形结构数据

JS使用递归将原始数据转换为树形结构数据

时间:2022-12-14 18:12:20浏览次数:57  
标签:index temp tree JS children 树形 ParentId 原始数据 节点

因为数据库中存放的数据终究全是扁平化的,因此获取后要手动将其改成树形结构,方便el-tree进行渲染。

假设数据如下(至少是要有节点ID和父节点ID)

 

 

 最终要达到如下效果(el-select的el-option下面直接写个树组件就能实现这个效果,为了方便展示在树组件外面加个滚动条)

 

 

 

递归函数如下:

    /**
     * 将后台获取到的表转换为树形组件所需的结构
     * @param arr value是递归数组,index是重新开始的位置,避免父级多次无效递归
     * @returns {{index, value: [{ParentId: *, children: *[], name, id: *}]}|{index: *, value: [{ParentId: *, children: *[], name, id: *}]}}
     */
    generateTreeNode(arr) {
      let index = arr.index
      let tree = arr.value
      //先获取第一个数组元素,尚不知道是叶节点还是树节点
      let temp = [{
        id: tree[index].NetId,
        name: tree[index].NetName,
        ParentId: tree[index].ParentId,
        children: []
      }]
      //从当前位置+1开始循环。因为这里要递归深层,每次传的数组是原始数组
      //所以需要获得结束递归后的新位置,方便下次循环使用
      for (let m = index + 1; m < tree.length; m++) {
        //如果第二个节点的父节点是当前已处理数组末尾元素,则说明第一个节点是父节点,第二个是其子节点
        //开始从第二个节点,进行递归
        if (tree[m].ParentId === temp[temp.length - 1].id) {
          let children = this.generateTreeNode({value: tree, index: m})
          // console.log('调用下一步', m, children)
          temp[temp.length - 1].children = children.value.slice()
          //-1,因为结束当前循环后默认m++,因此要往回退一位
          m = children.index - 1
        } //存在两种情况,若是子节点之间,则父节点相同,推入
        //若是两个同级树节点,因为子节点已经结束了递归,所以这里推入的是父级数组
        else if (tree[m].ParentId === tree[m - 1].ParentId ||
            tree[m].ParentId === temp[temp.length - 1].ParentId) {
          // console.log('相同情况下的调用:', m, tree.length)
          temp.push({
            id: tree[m].NetId,
            name: tree[m].NetName,
            ParentId: tree[m].ParentId,
            children: []
          })
        } //若下个节点的父节点和当前节点不对,则说明这一组的子节点已结束,结束递归
        else if (tree[m].ParentId !== tree[m - 1].ParentId) {
          return {value: temp, index: m}
        }
      }
      console.log('这里是树形最终结果', temp)
      return {value: temp, index: tree.length}
    },

属性名更改为各自的结果即可。这个递归(实际上在循环那里m=index+1,这就表示这也是可以嵌套循环的来做的,只要你提前知道他有多少层)个人测试,4层数据200余行大概用了0.28ms(主要时间是后台请求时间)

 

不过这个存在一个问题,那就是极度依赖原始数据的排列顺序,因为是事先假设全部顺序排列的。

如果遇到下面这种情况,原本在某个父节点下的子节点,其【父节点】发生了变化,但它本身的id不变(顺序不变),这就会导致该递归终止,(因为我们是比较父节点是否相同来做判断的。这里它一层层得向上比较都不存在的话,就会直接终止)

 

 

 

 

因此你最好还是先刷一遍全部数据进行分组,再刷分组进行比较来形成树,这样就可以避免因为顺序问题而导致失败

可以想象为,第一种方法是先从根节点开始,然后一路衍生至一侧最底下的子节点,然后子节点结束后往上,第二组子节点,从左到右;

第二种方法就是全部从子节点开始,分组后一层层往上设置其对应的父节点,最终到达根节点(从下往上)。后者感觉明显要花时间了……想想咋实现吧,下次随笔写

标签:index,temp,tree,JS,children,树形,ParentId,原始数据,节点
From: https://www.cnblogs.com/ricardox3/p/16982889.html

相关文章