關於樹狀結構數據的一些常用處理,比如找所有父級和子級,一維數組轉無限級樹狀結構


樹狀結構數據在日常開發是最經常遇到的數據,比如一些后台管理系統左側菜單就是一個樹狀結構的數據,這些數據的特點有,可以無限的子節點,父級與子級一般會存在上級關系,比如子級的屬性會有父級的唯一標識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]

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM