【算法解析】js 扁平数据 转 树形数据

在项目开发过程中,都会遇到树形数据结构与扁平数据结构的转换。

今天就分享一下,扁平数据结构转树形数据结构的方法


01、回顾数据结构

扁平数据结构

 
[{id:1, pid:0, name:'沃尔玛'},
 {id:2, pid:1, name:'生鲜区'},
 {id:3, pid:1, name:'日用品区'},
 {id:4, pid:2, name:'鱼'},
 {id:5, pid:2, name:'牛肉'},
 {id:6, pid:3, name:'卫生纸'},
 {id:7, pid:3, name:'牙刷'},
 {id:8, pid:7, name:'电动牙刷'},
 {id:9, pid:7, name:'普通牙刷'}]


树形数据结构
 

[{id:1, pid:0, name:'沃尔玛', childrens:[
      {id:2, pid:1, name:'生鲜区', childrens:[
        {id:4, pid:2, name:'鱼'},
        {id:5, pid:2, name:'牛肉'}
      ]},
      {id:3, pid:1, name:'日用品区',childrens:[
          {id:6, pid:3, name:'卫生纸'},
          {id:7, pid:3, name:'牙刷'}
        ]}
    ]}



02、扁平转树形

注:使用此方法,要求扁平数据中的id,必须进行升序排列

核心思想:
就是使用了Map来存储不同的id,对应的所在的内存地址,根据对应pid的值,找到你要加入到对象对应的位置。


思路 ( 递归方法 ):
1、申明一个Map对象,pid,outputObj三个变量
 

var map = new Map(); //存在id,对应所在的内存地址
var outputObj,pid;



2、循环数组,取出每个对象对应的pid
 

for(var i = 0; i<data.length;i++){
       pid = data[i].pid;



3、判断对应的pid是否已经存在Map中,如果存在,判断childrens属性是否存在,不存在,创建一个childrens属性; 将当前对象克隆到一个新对象,加入到childrens中。并且,将当前对象的id加入到Map中(重点)
 

if(map.has(pid)){
   //存在,将此信息,加入到对应id=pid的对象上的children
   if (!map.get(pid).childrens) //添加childrens属性
          map.get(pid).childrens = [];
   var obj = new Object(data[i]);
   map.get(pid).childrens.push(obj);
   //通过pid在Map中查找,并将当前对象,加入到对应的childres属性
   map.set(data[i].id,obj);
   //重点(必须也加入Map):将当前id及对应的对象,存入Map对象中
 }


4、判断pid不在Map中存在,并且pid为0;创建一个新的对象,且将id存入Map中
 

else if(!map.has(pid)&&pid==0){
  //这里处理pid不存在,且pid 为0的处理,pid不存在,且不为0的,程序不考虑这种情况
  outputObj = new Object(data[i]);
  map.set(data[i].id,outputObj);
  //将id添加到Map中
  TreeData.push(outputObj);
  //加入到要返回的数组中
}



完整代码如下:

function GetTreeData(data){
        var TreeData=[];
        var map = new Map(); //存在id,对应所在的内存地址
        var outputObj,pid;
        for(var i = 0; i<data.length;i++){
            pid = data[i].pid;
            if(map.has(pid)){
                //存在,将些信息,加入到对应id=pid的对象上的children
                if (!map.get(pid).childrens)
                    map.get(pid).childrens = [];
                var obj = new Object(data[i]);
                map.get(pid).childrens.push(obj);
                map.set(data[i].id,obj);
            }else if(!map.has(pid)&&pid==0){
                //这里处理pid不存在,且pid 为0的处理,pid不存在,且不为0的,程序不考虑这种情况
                outputObj = new Object(data[i]);
                TreeData.push(outputObj);
                map.set(data[i].id,outputObj);
            }
        }
        return TreeData;
    }



03、示例代码

写了一个DEMO

若pid对应的值,id没有,使用上面的转换方法,将忽略这条数据;
如下:{id:6, pid:13, name:'卫生纸'}

代码如下:

var data=[{id:1, pid:0, name:'沃尔玛'},
        {id:2, pid:0, name:'生鲜区'},
        {id:3, pid:1, name:'日用品区'},
        {id:4, pid:2, name:'鱼'},
        {id:5, pid:2, name:'牛肉'},
        {id:6, pid:13, name:'卫生纸'},
        {id:7, pid:3, name:'牙刷'},
        {id:8, pid:7, name:'电动牙刷'},
        {id:9, pid:7, name:'普通牙刷'}];
    var TreeData = GetTreeData(data);
    console.log(TreeData);
    function GetTreeData(data){
        var TreeData=[];
        var map = new Map(); //存在id,对应所在的内存地址
        var outputObj,pid ;
        for(var i = 0; i<data.length;i++){
            pid = data[i].pid;
            if(map.has(pid)){
                //存在,将些信息,加入到对应id=pid的对象上的children
                if (!map.get(pid).childrens)
                    map.get(pid).childrens = [];
                var obj = new Object(data[i]);
                map.get(pid).childrens.push(obj);
                map.set(data[i].id,obj);
            }else if(!map.has(pid)&&pid==0){
                //这里处理pid不存在,且pid 为0的处理,pid不存在,且不为0的,程序不考虑这种情况
                outputObj = new Object(data[i]);
                TreeData.push(outputObj);
                map.set(data[i].id,outputObj);
            }
        }
        return TreeData;
    }



视频讲解:https://www.bilibili.com/video/BV1y5411n7EH/



如果喜欢这篇文章,欢迎添加下角“公众号” ,可以第一时间获到文章推送

 

bug收集

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bug收集

谢谢老板的鼓励,我会继续加油

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值