将一维数组转换成树形结构数组方法总结

我们在开发中经常会处理数组,特别是后端传给我们的扁平化数组,然后将它处理为多维结构的数组

将扁平化数组转换成树形结构数组的n中方法

原始数据

var arr = [
  { id: 1, pid: 0, text: '一级1' },
  { id: 2, pid: 0, text: '一级2' },
  { id: 3, pid: 1, text: '二级1-1' },
  { id: 4, pid: 1, text: '二级1-2' }
  { id: 5, pid: 2, text: '二级2-1' },
  { id: 6, pid: 2, text: '二级2-2' }
  { id: 7, pid: 3, text: '三级1-1-1' },
  { id: 8, pid: 7, text: '四级1-1-1-1' }
  { id: 9, pid: 8, text: '五级1-1-1-1-1' },
  { id: 10, pid: 9, text: '六级1-1-1-1-1' }
]

方法1

使用ES5的的数组新方法filter两层嵌套来实现

// 使用filter过滤方法
 // 使用filter过滤方法
(function(){
    let x = 0;
    let arrayToThree = function(arr){
      // 先把要格式化的数组进行深拷贝,由于这种方式是操作元素组的,所以需要先拷贝一份
      let cloneArr = JSON.parse(JSON.stringify(arr));
      // 然后使用filter进行过滤
      return cloneArr.filter(p=>{
        // 嵌套filter,为数组的每一项进行一次整个数组的判断
        // 获取整个数组中是当前项的子集然后返回
        const _getChild = cloneArr.filter((c) => {x++;return c.pid == p.id});
        // 判断获取的数组是否有值如果有值,赋值给当前项的children
        _getChild.length && (p.children = _getChild);
        // 然后返回顶级的项
        return p.pid === 0;
      });
    };
    let getTree = arrayToThree(arr);
    console.log(getTree);
    console.log(x);
    //100

    // 此方法虽然最简单,但是循环次数却很多,虽然所有循环都是js内部处理
})();

方法2

(function(){
  let x = 0;
  let getArr = JSON.parse(JSON.stringify(arr));
  // 定义方法
  let arrayToTree = function(arr){
    // 获取所有顶级分类,然后组成数组
    let parents = arr.filter(v=> v.pid === 0);
    // 获取所有非顶级分类,组成数组
    let children = arr.filter(v => v.pid !== 0);
    // 定义递归方法, 传入参数,父级数组,和子集数组
    function dataToTree(p, c){
      // 循环遍历父级数组
      p.forEach(p_v =>{
        // 循环遍历子集数组
        c.forEach((c_v, c_i) => {
          x++;
          // 判断当前的子项是否为当前的父项的子元素
          if(c_v.pid === p_v.id){

            // 如果是那么判断当前,当前父类项是否有children 字段
            if(!p_v.children){
              // 如果没有初始化为空数组
              p_v.children = [];
            }
            // 然后把当前的子类项推到父类的children数组中
            p_v.children.push(c_v);
            // 在执行递归调用当前方法,把当前子类项以数组的形式作为第一个参数传入,然后把所有的子集数组作为第二个参数传入,从新遍历所有子类数组中是否有当前子类的下一级
            // dataToTree([c_v], children);

            /* 为了减少遍历的次数可以把当前项从子类型中删除 */
            // 然后把所有的子集数组深拷贝一份,因为数组中的项是对象属于引用类型的
            let _c = JSON.parse(JSON.stringify(c));
            //然后把当前子类项从整体的子类数组中剔除
            _c.splice(c_i, 1);
            // 在执行递归调用当前方法,把当前子类项以数组的形式作为第一个参数传入,然后把所有的子集数组作为第二个参数传入,从新遍历所有子类数组中是否有当前子类的下一级
            dataToTree([c_v], _c);
          }
        });
      });
    }
    dataToTree(parents, children);
    return parents;
  };
  let getTree = arrayToTree(getArr);
  console.log(getTree);
  console.log(x);
  // 62
})();

方法3

(function(){
  let x = 0;
  let getArr = JSON.parse(JSON.stringify(arr));
  // 定义递归的方法
  let arrayToTree = (arr, id) => {
    // 使用ES6中数组的reduce方法来实现
    // reduce遍历数组中的所有行,并且返回每一项合起来的结果
    return arr.reduce((res, current)=>{
      x++;
      //判断当前值的pid是否和传入的id相同
      if(current.pid === id){
        // 如果相同直接给当前的项增加children属性,他的值是递归调用该方法返回的数组,从新递归调用该方法,把数组,和当前项的id作为参数传入
        current.children = arrayToTree(arr, current.id);
        // 返回拼接好的数组
        return res.concat(current);
      }
      // 最后返回处理后的数组
      return res;
    }, []);
  }
  console.log(arrayToTree(getArr, 0));
  console.log(x);
  // 110
})();

方法4

(function(){
  let x = 0;
  var toTree = function(tarArray){
    // 为了防止改变原数组,需要深拷贝一份数组
    tarArray = JSON.parse(JSON.stringify(tarArray));
    // 首先定义一个变量,把数组中的每一项以当前项的id为下标存入对象中
    var obj = {}
    // 遍历数组并存入项
    tarArray.map((item,index)=>{
      x++;
      obj[item.id] = item;
    });
    // 定义一个新数组,用来保存生成的树形数组
    var newArr = [];
    //再次遍历数组进行检测
    tarArray.forEach((item, index)=>{
      x++;
      // 先去刚才的对象中查找当前项有没有父级
      let curItemParent = obj[item.pid];
      if(curItemParent){
        // 如果有那么就判断当前的父级有没有children属性,如果没有取空数组,如果有取本身children
        curItemParent.children = curItemParent.children || [];
        // 然后把当前项推入到他的父级的children 数组中
        curItemParent.children.push(item);
      }else{
        // 如果没有证明这个是根节点,直接放到新数组中
        newArr.push(item);
      }
    });
    console.log(newArr)
  }
  toTree (arr);
  console.log(x);
  // 20
  // 此方法是循环次数最少的,但是需要额外定义一个对象来做对比
})();

方法5

(function(){
  let x = 0;
  // 首先定义方法,传入要转换的数组,和根节点的pid号
  var arrayToTree = function(arr, rootId){
    // 这里主要是使用的es5新增的特性来深拷贝数组,如果做兼容需要使用深拷贝方法
    arr = JSON.parse(JSON.stringify(arr));
    //定义一个初始化对象,其中children用来存储树形化的数组
    var newObj = {id: rootId, children: []};
    // 定义一个递归的方法,并传入当前的父级项
    var toTree = function(parObj){
      // 获取数组的最后一个值得下标
      var i = arr.length - 1;
      // 获取当前父级项的id
      var id = parObj.id;
      // 从数组右边往左循环
      while(i > -1){
        x++;
        //获取当前遍历的项
        var item = arr[i];
        // 判断当前项是否是当前父级项的子集
        if(item.pid === id){
          // 如果是,然后判断当前父级项是否有children字段,如果有直接用,如果没有给children赋值为一个空数组
          parObj.children = parObj.children || [];
          // 然后把当前项放到当前父级的children数组的最前方
          parObj.children.unshift(item);
          // 然后删除整个数组中的当前项,为了减少递归的循环次数提高性能
          arr.splice(i, 1);
          // 然后再调用方法本身,把当前项传入,进行下一轮的查找,找到数组中属于当前项的子集并进行操作
          toTree(item);
        }
        i--;
      }
    };
    // 初次调用传入初始化的对象
    toTree(newObj);
    return newObj.children;
  };
  console.log(arrayToTree(arr, 0));
  console.log(x);
  // 55
})();

方法6

(function(){
  let x = 0;
  // 首先定义方法,传入要转换的数组,和根节点的pid号
  var arrayToTree = function(arr, rootId){
    // 这里主要是使用的es5新增的特性来深拷贝数组,如果做兼容需要使用深拷贝方法
    arr = JSON.parse(JSON.stringify(arr));
    //定义一个初始化对象,其中children用来存储树形化的数组
    var newObj = {id: rootId, children: []};
    // 定义一个递归的方法,并传入当前的父级项
    var toTree = function(parObj){
      // 获取数组的最后一个值得下标
      var i = 0;
      // 获取当前父级项的id
      var id = parObj.id;
      // 从数组右边往左循环
      while(i < arr.length){
        x++;
        //获取当前遍历的项
        var item = arr[i];
        // 判断当前项是否是当前父级项的子集
        if(item.pid === id){
          // 如果是,然后判断当前父级项是否有children字段,如果有直接用,如果没有给children赋值为一个空数组
          parObj.children = parObj.children || [];
          // 然后把当前项放到当前父级的children数组的最前方
          parObj.children.push(item);
          // 然后删除整个数组中的当前项,为了减少递归的循环次数提高性能
          arr.splice(i, 1);
          i--;
          // 然后再调用方法本身,把当前项传入,进行下一轮的查找,找到数组中属于当前项的子集并进行操作
          toTree(item);
        }
        i++;
      }
    };
    // 初次调用传入初始化的对象
    toTree(newObj);
    return newObj.children;
  };
  console.log(arrayToTree(arr, 0));
  console.log(x);
  // 37
})();
  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值