在工作中經常會遇到樹形結構的對象轉為數組或者數組轉為樹形對象的需求,那么如何實現呢?
1、首先是要將一個具有樹形結構的數組轉化為樹形結構的對象
// 將一個扁平化的對象數組,轉化為樹形結構 // 現在有一個對象組成的數組,每個元素有id屬性和parent_id屬性,根據其id屬性和parent_id屬性,將其轉換為樹結構的對象 const arr = [ { id: '1', parent_id: 'root', name:'abc' }, { id: '2', parent_id: 'root', name:'abc' }, { id: '1-1', parent_id: '1', name:'abc' }, { id: '1-2', parent_id: '1', name:'abc' }, { id: '1-1-1', parent_id: '1-1', name:'abc' }, { id: '1-1-2', parent_id: '1-1', name:'abc' }, { id: '1-2-1', parent_id: '1-2', name:'abc' }, { id: '2-1', parent_id: '2', name:'abc' }, { id: '2-2', parent_id: '2', name:'abc' }, { id: '2-1-1', parent_id: '2-1', name:'abc' }, { id: '2-2-1', parent_id: '2-2', name:'abc' }, { id: '2-2-1-1', parent_id: '2-2-1', name:'abc' }, { id: '2-2-1-2', parent_id: '2-2-1', name:'abc' }, { id: '2-2-1-2-1', parent_id: '2-2-1-2', name:'abc' }, { id: '2-3', parent_id: '2', name:'abc' }, { id: '2-3-1', parent_id: '2-3', name:'abc' }, { id: '3', parent_id: 'root', name:'abc' }, ]; // 將這樣一個數組,變成能夠以樹形展示的對象 //先將數組中的每一個節點放到temp對象中(創建set) //即數組中有{id: '2-3', parent_id: '2',...}這樣一個節點,需要將他放到temp中變成 '2-3': {id: '2-3', parent_id: '2',...}這種JSON結構 //直接遍歷整個temp對象,通過這句代碼 temp[temp[i].parent_id].children[temp[i].id] = temp[i]; //將當前子節點與父節點建立連接。是因為我們保證了父節點一定在子節點前, //那么當子節點出現的時候就直接可以用temp[temp[i].parent_id]來查找到父節點這個時候先父節點的children對象中添加一個引用即可。 function buildTree(array,id,parent_id) { console.time('123'); // 創建臨時對象 let temp = {}; // 創建需要返回的樹形對象 let tree = {}; // 先遍歷數組,將數組的每一項添加到temp對象中 for(let i in array) { temp[array[i][id]] = array[i]; } /* 上面也可以寫成 for(let i=0;i<array.length;i++) { temp[array[i][id]] = array[i]; } */ // 遍歷temp對象,將當前子節點與父節點建立連接 for(let i in temp) { // 判斷是否是根節點下的項 if(temp[i][parent_id] !== 'root') { if(!temp[temp[i][parent_id]].children) { temp[temp[i][parent_id]].children = new Array(); } temp[temp[i][parent_id]].children.push(temp[i]); } else { tree[temp[i][id]] = temp[i]; } } /* 上面也可以寫成 for(let i=0;i<array.length;i++) { temp[array[i][id]] = array[i]; } */ console.timeEnd('123'); return tree; } const obj = buildTree(arr, 'id', 'parent_id'); console.log(obj);
2、樹形結構轉化為一維扁平數組
const treeObj = { id: '0', name: '0', children:[ { id: '1', name:'anc', children:[ { id: '1-1', name:'anc', children:[ { id: '1-1-1', name:'anc', }, { id: '1-1-2', name:'anc' }, ] }, { id: '1-2', name:'anc', children:[ { id: '1-2-1', name:'anc', }, { id: '1-2-2', name:'anc' }, ] }, ] }, { id: '2', name:'anc', children:[ { id: '2-1', name:'anc', children:[ { id: '2-1-1', name:'anc', }, { id: '2-1-2', name:'anc' }, ] }, { id: '2-2', name:'anc', children:[ { id: '2-2-1', name:'anc', children: [ { id: '2-2-1-1', name:'anc', }, { id: '2-2-1-2', name:'anc' }, ] }, { id: '2-2-2', name:'anc' }, ] }, { id: '2-3', name:'anc', children:[ { id: '2-3-1', name:'anc', }, { id: '2-3-2', name:'anc' }, ] }, ] }, { id: '3', name:'anc', children:[] } ] }; // 將treeObj中的所有對象,放入一個數組中,要求某個對象在另一個對象的children時,其parent_id是對應的另一個對象的id // 其原理實際上是數據結構中的廣度優先遍歷 function tree2Array(treeObj, rootid) { const temp = []; // 設置臨時數組,用來存放隊列 const out = []; // 設置輸出數組,用來存放要輸出的一維數組 temp.push(treeObj); // 首先把根元素存放入out中 let pid = rootid; const obj = deepCopy(treeObj); obj.pid = pid; delete obj['children']; out.push(obj) // 對樹對象進行廣度優先的遍歷 while(temp.length > 0) { const first = temp.shift(); const children = first.children; if(children && children.length > 0) { pid = first.id; const len = first.children.length; for(let i=0;i<len;i++) { temp.push(children[i]); const obj = deepCopy(children[i]); obj.pid = pid; delete obj['children']; out.push(obj) } } } return out } console.log(tree2Array(treeObj, 'root')) // 深拷貝 function deepCopy(obj){ // 深度復制數組 if(Object.prototype.toString.call(obj) === "[object Array]"){ const object=[]; for(let i=0;i<obj.length;i++){ object.push(deepCopy(obj[i])) } return object } // 深度復制對象 if(Object.prototype.toString.call(obj) === "[object Object]"){ const object={}; for(let p in obj){ object[p]=obj[p] } return object } }