js将数组对象转化为树形结构

6,308 阅读1分钟

原数组对象

// list: 数组对象
// id: 每条数据的id
// pid: 每条数据的父节点对应字段
// pid:null 没有父节点的数据

   const list = [
        { id: 04, pid: 03 },
        { id: 01, pid: null },
        { id: 02, pid: null },
        { id: 03, pid: 01 },
        { id: 05, pid: 01 },
        { id: 06, pid: 03 },
        { id: 07, pid: 02 },
        { id: 09, pid: 02 },
        { id: 10, pid: 07 },
    ]

转换为树形结构

[
    {
        "id": 1,
        "pid": null,
        "children": [
            {
                "id": 3,
                "pid": 1,
                "children": [
                    {
                        "id": 4,
                        "pid": 3
                    },
                    {
                        "id": 6,
                        "pid": 3
                    }
                ]
            },
            {
                "id": 5,
                "pid": 1
            }
        ]
    },
    {
        "id": 2,
        "pid": null,
        "children": [
            {
                "id": 7,
                "pid": 2,
                "children": [
                    {
                        "id": 10,
                        "pid": 7
                    },
                    {
                        "id": 11,
                        "pid": 7
                    }
                ]
            },
            {
                "id": 9,
                "pid": 2
            }
        ]
    }
]

思路:将有父子关系的数组数据先分为两类,一类是没有父节点的数据(parent),另一类是有父节点的数据(children),然后通过遍历parent,对每一个父节点在children查找对应的子节点,并将其放入父节点的children中(这里我的是以children表示子节点),然后每个子节点又作为一个父节点来重复之前的动作。

方法一:

function toTree(data) {             
   let result = []            
   //如果值是 Array,则为true; 否则为false。           
   if(!Array.isArray(data)) {                  
       return result       
   }                
   //根据父节点进行拼接子节点,             
   data.forEach(item => {                
     console.log(item);                
     delete item.children; //已经有的话就删掉              
   });               
   //把每一项的引用放入map对象里             
   let map = {};             
   data.forEach(item => {                 
        map[item.id] = item;          
   });                
   //再次遍历数组 决定item的去向             
   data.forEach(item => {                
     let parent = map[item.pid];                
     if(parent) {                      
      // 如果 map[item.pid] 有值 则 parent 为 item 的父级
      // 判断 parent 里有无children 如果没有则创建 如果有则直接把 item push到children里  
      (parent.children || (parent.children = [])).push(item);                 
     } else {                 
       // 如果 map[item.pid] 找不到值 说明此 item 为 第一级              
       result.push(item);                  
     }              
   });  
   return result;          
}            
console.log(toTree(list))

方法二:

function toTree(data) {              
  let result = [];              
  let obj = {};              
  data.forEach(item => {                 
    obj[item.id] = Object.assign(item, obj[item.id] || {});                
    if (item.pid) {                    
       let parent = obj[item.pid] || {};        
       parent.child = parent.child || [];                     
       parent.child.push(item);                
       obj[item.pid] = parent;                
    } else {                    
       result.push(obj[item.id])              
    }            
  })              
  return result;           
}          
console.log(toTree(list))