Js 將陣列按父子關係轉換為物件樹
阿新 • • 發佈:2019-02-02
這是一道遇到過兩次的前端筆試題,第一次是在哪裡記不清了,第二次是在今天上午多益網路的筆試中,兩次試題的具體內容稍微有差別,因為時間和IDE 的原因都沒能解出正確答案。事後又花點時間搗鼓一下,整理出兩種解法,記錄在這裡。
1. 問題的輸入與輸出
首先來看一下這個問題的輸入和輸出:
// 輸入 var nodes = [ {id: 10, title: 'dw10', parentId: 4}, {id: 2, title: 'dw2', parentId: 0}, {id: 4, title: 'dw4', parentId: 2}, {id: 12, title: 'dw12', parentId: 2}, {id: 8, title: 'dw8', parentId: 4} ];
// 輸出 { "id": 2, "title": "dw2", "parentId": 0, "children": [ { "id": 12, "title": "dw12", "parentId": 2 }, { "id": 4, "title": "dw4", "parentId": 2, "children": [ { "id": 8, "title": "dw8", "parentId": 4 }, { "id": 10, "title": "dw10", "parentId": 4 } ] } ] }
2. 解法一:廣度優先搜尋
第一種解法的步驟如下:
(1)首先,按照每一項的parentId 數值給輸入陣列排序。
(2)將排序後的陣列的第一條資料作為根元素,遍歷陣列,比較當前記錄的parentId 和結果物件中的id 依次將剩下的資料插入到合適的位置上,在尋找合適位置的過程中使用的是廣度優先搜尋的方法。
此種方法的時間複雜度較高,程式碼量頗大,實現程式碼如下:
var nodes = [ {id: 10, title: 'dw10', parentId: 4}, {id: 2, title: 'dw2', parentId: 0}, {id: 4, title: 'dw4', parentId: 2}, {id: 12, title: 'dw12', parentId: 2}, {id: 8, title: 'dw8', parentId: 4} ]; function findPos(obj, id) { // 廣度優先搜尋遍歷當前物件 var queue = [], temp; if(obj.id === id) { return obj; } queue.push(obj.children); while(queue) { temp = queue.shift(); var res = findChildIndex(id, temp); if(res) { return res; } for(var i = 0; i < temp.length; i++) { queue.push(temp[i]); } } } // 判斷一個數字是否在children 列表內 function findChildIndex(id, arr) { if(arr.id && id === arr.id) { return arr; } for(var i = 0; i < arr.length; i++) { if(id === arr[i].id) { return arr[i]; } } return null; } // sort function cmp(a, b) { return a.parentId - b.parentId; } nodes.sort(cmp); var resObj = nodes[0]; for(var i = 1, len = nodes.length; i < len; i++) { var findRes = findPos(resObj, nodes[i].parentId); if(findRes) { if(!findRes.children) { findRes.children = []; } findRes.children.push(nodes[i]); } } console.log(resObj);
3. 解法二:從後向前
在控制時間複雜度的情況下,上面提到的方法就無法達到要求。於是又開始思考第二種方法,排序後從後向前遍歷陣列。如果把最終的物件想象成一顆樹的話,這個方法就相當於從葉子節點開始到根節點逐漸建立一棵完整的樹。
與上一個方法相比,該方法時間複雜度較低,且程式碼量不大,實現程式碼如下:
var nodes = [
{id: 10, title: 'dw10', parentId: 4},
{id: 2, title: 'dw2', parentId: 0},
{id: 4, title: 'dw4', parentId: 2},
{id: 12, title: 'dw12', parentId: 2},
{id: 8, title: 'dw8', parentId: 4}
];
// sort
function cmp(a, b) {
return a.parentId - b.parentId;
}
nodes.sort(cmp);
var midObj = {};
// 從後向前遍歷
for(var i = nodes.length - 1; i >= 0; i--) {
var nowPid = nodes[i].parentId;
var nowId = nodes[i].id;
// 建立當前節點的父節點的children 陣列
if(midObj[nowPid]) {
midObj[nowPid].push(nodes[i]);
} else {
midObj[nowPid] = [];
midObj[nowPid].push(nodes[i]);
}
// 將children 放入合適的位置
if(midObj[nowId]) {
nodes[i].children = midObj[nowId];
delete midObj[nowId];
}
}
console.log(midObj[0][0]);