关于树状结构数据的一些常用处理,比如找所有父级和子级,一维数组转无限级树状结构

树状结构数据在日常开发是最经常遇到的数据,比如一些后台管理系统左侧菜单就是一个树状结构的数据,这些数据的特点有,可以无限的子节点,父级与子级一般会存在上级关系,比如子级的属性会有父级的唯一标识id,我这里总结了,一维数组转无限级树状结构,树状结构转一维数组,根据指定属性值找所有的父级或者子级数据,有不对的地方,还望大佬们多多指点.

一、一维数组转无限级树状结构

 1、 使用递归法: 数据会存在上下级关系,否则无法转换

 1 let data1 = [
 2     {id:1,pid:0,name:"name1"},
 3     {id:2,pid:0,name:"name2"},
 4     {id:3,pid:2,name:"name3"},
 5     {id:4,pid:1,name:"name4"},
 6     {id:5,pid:4,name:"name5"},
 7     {id:6,pid:5,name:"name6"},
 8     {id:7,pid:5,name:"name6"},
 9     {id:8,pid:7,name:"name6"},
10 
11 ]
12 //递归法:一维数组转无限极树状结构
13 /**
14  * 
15  * @param data 数据源,一维数据
16  * @param idKeys 要匹配所在项的唯一idkey 属性字段,比如idkeys ='id',
17  * @param pidKeys 要匹配所在项的上级 pidkey 属性字段,比如pidkeys = 'pid',
18  * @param pid  要匹配所在项目的上级pidkey 字段的值,比如 pid = 0
19  * @param leve 当前所在树状结构的层级数
20  */
21 export function oneToTree<T extends {[key:string]:any}>(data:T[],idKeys?:string,pidKeys?:string,pid?:any,leve?:number){
22     let idKey = idKeys||"id"
23     let pidKey = pidKeys||'pid'
24     let leveKey = "$leve"
25     let childrenKey = "children"
26     let pidData = pid||0
27     let leves = leve||1;
28     if(!Array.isArray(data)) return data;
29     type resI = T&{$leve:number,children:resI[]};//使用交叉类型,新增了两个字段$live,children
30     let resArr:Array<resI> =[];
31     data.forEach( (itme:any)=> {
32         if (itme[pidKey] === pidData) {
33             itme[leveKey] = leves;
34             itme[childrenKey] = oneToTree(data, idKey, pidKey, itme[idKey], leves + 1);
35             resArr.push(itme)
36         }
37     })
38     
39     return resArr
40 
41 }
42 let data1 = oneToTree(data1)

 

二、数状结构数据转一维数组

 1 /**
 2  * @param data 数据源(数状结构)
 3  * @param childrenKeys : 每项的子级字段key,默认为:children
 4  */
 5 export function treeToOneArr<T extends {[key:string]:any}>(data:T[],childrenKey?:string):T[]{
 6     let resArr:T[] = [];
 7     childrenKey = childrenKey||'children'
 8     for(let i=0;i<data.length;i++){
 9         let itme:any = data[i];// 这里有点不好,用了any 类型,返回数据的成员掉失了类型检测,
10         if(Array.isArray(itme[childrenKey])){
11             let child:T[] = itme[childrenKey];
12             itme[childrenKey] = [];
13             resArr = resArr.concat(itme).concat(treeToOneArr(child,childrenKey))
14         }else{
15             resArr.push(itme)
16         }
17     }
18 
19     return resArr
20 }
21 
22 console.log(treeToOneArr(data4));

 

三、 一维数组,找所有上级或者下级指定数据

 (1. ) :每项之间依赖字段存在上下层关系

 (2. ):给出指定字段的值找出当前项所有的下级/上级,匹配项的指定字段的值或者匹配的所有项

let data1 = [
    {id:1,pid:0,name:"name1"},
    {id:2,pid:0,name:"name2"},
    {id:3,pid:2,name:"name3"},
    {id:4,pid:1,name:"name4"},
    {id:5,pid:4,name:"name5"},
    {id:6,pid:5,name:"name6"},
    {id:7,pid:5,name:"name6"},
    {id:8,pid:7,name:"name6"},

]
/**
 * 一维数组,每项之间依赖字段存在上下层关系,根据依赖项字段,给出指定字段的值找出当前项所有的下级/上级指定字段/所有项
 * @param data ,数据源,一维数组
 * @param value  给出要与依赖字段(PidKeys) 匹配的值
 * @param idKeys    所在项的唯一key ,也是作为下级的依赖字段,默认为id,比如:id,pid
 * @param pidKeys   要与指定value 匹配的字段(不是值,是字段key),也是所在项的依赖字段,默认为pid,比如,id,pid
 * @param reKeys  要返回的指定字段值,默认为 和idkeys一样的
 * @param field    是否要返回匹配项的所有字段,默认为false
 */
/*
    1. 找所有上级:把每项的存在依赖关系的字段(如pid)作为匹配字段(idkeys),依赖字段作为为匹配字段
    2. 找所有下级:和上级刚好相反
*/
export function findTreenField<T extends {[key:string]:any}>(data:T[],value:any,idKeys?:string,pidKeys?:string,reKeys?:string,field?:boolean){
    let idKey = idKeys||"id"
    let pidKey = pidKeys||"pid"
    let reKey = reKeys||idKey;
    let fields = field||false
    if(!value ||value===0) return [];
    if(!Array.isArray(data)) return [];
    var resArr:any[] = [];
    for (let i = 0; i < data.length; i++) {
        let itme:T = data[i];
        if(itme[pidKey]===value){
            if(fields){
                resArr.push(itme);
            }else{
                resArr.push(itme[reKey]);
            }            
            resArr = resArr.concat(findTreenField(data, itme[idKey],idKey, pidKey, reKey,fields))
        }
        
    }
    return resArr
}
// 找所有子级
console.log(findTreenField(data1,5)) ;//[6, 7, 8]
//找所有父级
console.log(findTreenField(data1,5,"pid","id")) ;//[4,1,0]

 

四、 树状结构数据,根据指定值找所有上级节点(只需要知道子节点的属性key)

1. 递归法

2. 思路: 先递归数组往下找,根据当前属性keys的值如果和value 相等,找到要匹配当前value 所在的项,退出当前循环, 把当前的项的属性kesy对应的值作为value 参数,递归循环,一层层往上找

 1 const data = [
 2     {id:1,children:[
 3         {id:1.1,children:null},
 4         {id:1.2,children:null},
 5         {id:1.3,children:[
 6             {id:1.31,children:null},
 7             {id:1.32,children:[
 8                 {id:1.321,children:[
 9                     {id:1.3211,children:null}
10                 ]},
11                 {id:1.322,children:null}
12             ]}
13         ]},
14     ]},
15    
16     {id:2,children:[
17         {id:2.1,children:[
18             {id:2.11,children:null},
19             {id:2.12,children:[
20                 {id:2.121,children:null}
21             ]},
22             {id:2.13,children:null},
23         ]},
24     ]},
25 ]
26 
27 /**
28  * 
29  * @param dataArr 数据源(数状结构tree)
30  * @param value  要匹配的值
31  * @param keys  与value 匹配的属性keys ,比如'id' ,'index' 对象的值
32  * @param rekeys  要返回的 属性 reskeys,比如'id' ,'index' 对应的值
33  * @param childrenKeys 子节点的属性,默认 children
34  */
35 export function findTreeParendId<T extends {[key:string]:any}>(dataArr:T[],value:any,keys:string,rekeys:string,childrenKeys?:string):Array<keyof T>{
36     let data = JSON.parse(JSON.stringify(dataArr));//避免引用,做深拷贝处理
37     var resArr:Array<keyof T> =  [];
38     let childrenKey = childrenKeys||'children';
39     if(data.length<0){
40         return resArr
41     }
42     let recursion = (arrs:T[],itmeId:any,parendId?:any)=>{
43         for(let i=0;i<arrs.length;i++){
44       
45             let itme:T = arrs[i]
46             if(itme[keys]===itmeId){
47                 resArr.unshift(itme[rekeys]);// 找到匹配的就加进去
48                 if(parendId){
49                     recursion(data,parendId)
50                 }
51                 break;//跳出当前循环
52             }else{
53                 //找不到,如果有子级,递归往下找
54                 if(itme[childrenKey]&& Array.isArray(itme[childrenKey])){
55                     recursion(itme[childrenKey],itmeId,itme[keys])
56                 }
57             }
58         }
59     }
60     recursion(data,value)
61     return resArr;
62 }
63 console.log(findTreeParendId(data,2.121,"id","id"));//[2, 2.1, 2.12, 2.121]

 

五、 树状结构数据,根据指定值找所有下级节点(只需要知道子节点的属性key)

 1、使用递归法

 2、实现思路和 第四个找所有父级节点是一样,但是实现有点不同(有更好的实现方法可以留言)

 1 const data = [
 2     {id:1,children:[
 3         {id:1.1,children:null},
 4         {id:1.2,children:null},
 5         {id:1.3,children:[
 6             {id:1.31,children:null},
 7             {id:1.32,children:[
 8                 {id:1.321,children:[
 9                     {id:1.3211,children:null}
10                 ]},
11                 {id:1.322,children:null}
12             ]}
13         ]},
14     ]},
15    
16     {id:2,children:[
17         {id:2.1,children:[
18             {id:2.11,children:null},
19             {id:2.12,children:[
20                 {id:2.121,children:null}
21             ]},
22             {id:2.13,children:null},
23         ]},
24     ]},
25 ]
26 
27 /**
28  * 
29  * @param data  数据源(数状结构tree)
30  * @param value    给出指定要匹配的值 比 1
31  * @param idkeys   被匹配的字段属性 ,比如:id(默认)
32  * @param reKeys   要返回的字段属性,比如 id(默认)
33  * @param childrenKeys  指定每项的子级字段,比如:children(默认)
34  */
35 export function findChildFiled<T extends {[key:string]:any}>(data:T[],value:any,idkeys?:string,reKeys?:string,childrenKeys?:string){
36     let idkey = idkeys||'id';
37     let reKey = reKeys||'id';
38     let childrenKey = childrenKeys||'children'
39     let arrRes:any[] = []; 
40     //2.对匹配的所在项,进行递归获取所有子项的指定字段值
41     let findReKeys = function(arr:T[]){
42         if(!Array.isArray(arr)) return arr;
43         for(let i =0;i<arr.length;i++){
44            let itme:T = arr[i];
45            arrRes.push(itme[reKey])
46            findReKeys(itme[childrenKey])
47         }
48     }
49     //1.先递归找到指定值的所在项
50     let findNode = function(arr:T[]){
51         if(!Array.isArray(arr)) return arr;
52         for(let i =0;i<arr.length;i++){
53             let itme:T = arr[i];
54             if(itme[idkey]===value){
55                 findReKeys([itme])
56                 break;
57             }else{
58                 findNode(itme[childrenKey])    
59             }
60           
61         }
62    }
63    findNode(data)
64    return arrRes
65 } 
66 console.log(findChildFiled(data,1.3));//[1.3, 1.31, 1.32, 1.321, 1.3211, 1.322]
67 console.log(findChildFiled(data,2.1));//[2.1, 2.11, 2.12, 2.121, 2.13]

 

posted @ 2020-08-28 09:56  天高任鸟飞吧  阅读(1253)  评论(0编辑  收藏  举报