>[success] # 把原始 list 轉換成樹形結構
~~~
1.以下數據結構中,id 代表部門編號,name 是部門名稱,parentId 是父部門
編號,為 0 代表一級部門,現在要求實現一個 convert 方法,把原始 list 轉換
成樹形結構,parentId 為多少就掛載在該 id 的屬性 children 數組下
~~~
~~~
// 原始 list 如下
let list =[
{id:1,name:'部門A',parentId:0},
{id:2,name:'部門B',parentId:0},
{id:3,name:'部門C',parentId:1},
{id:4,name:'部門D',parentId:1},
{id:5,name:'部門E',parentId:2},
{id:6,name:'部門F',parentId:3},
{id:7,name:'部門G',parentId:2},
{id:8,name:'部門H',parentId:4}
];
const result = convert(list, ...);
// 轉換后的結果如下
let result = [
{
id: 1,
name: '部門A',
parentId: 0,
children: [
{
id: 3,
name: '部門C',
parentId: 1,
children: [
{
id: 6,
name: '部門F',
parentId: 3
}, {
id: 16,
name: '部門L',
parentId: 3
}
]
},
{
id: 4,
name: '部門D',
parentId: 1,
children: [
{
id: 8,
name: '部門H',
parentId: 4
}
]
}
]
},
···
];
~~~
>[danger] ##### 用遞歸解決
~~~
let list = [
{ id: 4, name: "部門D", parentId: 1 },
{ id: 5, name: "部門E", parentId: 2 },
{ id: 6, name: "部門F", parentId: 3 },
{ id: 7, name: "部門G", parentId: 2 },
{ id: 1, name: "部門A", parentId: 0 },
{ id: 2, name: "部門B", parentId: 0 },
{ id: 3, name: "部門C", parentId: 1 },
{ id: 8, name: "部門H", parentId: 4 },
];
// 遞歸思路先找一個節點下的所有,即當前根節點為 0
// 就找到 第一個根節點中值為{ id: 1, name: "部門A", parentId: 0 }
// 開始遞歸找到 當前id:1 節點的子節點,即其他parentId 為1的節點
// 依次開始當找到 { id: 4, name: "部門D", parentId: 1 } 第一個
// parentId 為1的節點繼續遞歸去找 parentId 4 的節點
function convert(source, parentId = 0) {
const ls = [];
for (let item of source) {
// 去找當前節點的子節點
if (parentId === item.parentId) {
// 這些去找它的子節點
const rs = convert(source, item.id);
// 把子節點拼接會現在節點
if (rs.length > 0) item.children = rs;
ls.push(item);
}
}
return ls;
}
console.log(convert(list));
~~~
>[danger] ##### 使用兩個filter 過濾
~~~
let list = [
{ id: 4, name: "部門D", parentId: 1 },
{ id: 5, name: "部門E", parentId: 2 },
{ id: 6, name: "部門F", parentId: 3 },
{ id: 7, name: "部門G", parentId: 2 },
{ id: 1, name: "部門A", parentId: 0 },
{ id: 2, name: "部門B", parentId: 0 },
{ id: 3, name: "部門C", parentId: 1 },
{ id: 8, name: "部門H", parentId: 4 },
];
// 依次去找每個節點下的子節點
// 比如找到 id為2的子節點 可以寫成 list.filter((item) => item.parentId === 2);
function convert(source, rootId = 0) {
return source.filter((rootNode) => {
const rs = source.filter((childrenNode) => {
return childrenNode.parentId === rootNode.id;
});
if (rs.length > 0) rootNode.children = rs;
return rootNode.parentId === rootId;
});
}
~~~
>[danger] ##### 利用map
~~~
let list = [
{ id: 4, name: "部門D", parentId: 1 },
{ id: 5, name: "部門E", parentId: 2 },
{ id: 6, name: "部門F", parentId: 3 },
{ id: 7, name: "部門G", parentId: 2 },
{ id: 1, name: "部門A", parentId: 0 },
{ id: 2, name: "部門B", parentId: 0 },
{ id: 3, name: "部門C", parentId: 1 },
{ id: 8, name: "部門H", parentId: 4 },
];
// 利用key value 形式
// 依次去循環找 到對應父節點,將當前節點插入回去父節點
function convert(source, rootId = 0) {
const map = list.reduce((res, v) => ((res[v.id] = v), res), {});
return source.filter((item) => {
if (item.parentId in map) {
const parentNode = map[item.parentId];
parentNode.children = parentNode.children || [];
parentNode.children.push(item);
}
return item.parentId === rootId;
});
}
console.log(convert(list));
~~~
>[info] ## 參考文章
[木易楊前端進階](https://muyiy.cn/question/program/88.html)
- 接觸數據結構和算法
- 數據結構與算法 -- 大O復雜度表示法
- 數據結構與算法 -- 時間復雜度分析
- 最好、最壞、平均、均攤時間復雜度
- 基礎數據結構和算法
- 線性表和非線性表
- 結構 -- 數組
- JS -- 數組
- 結構 -- 棧
- JS -- 棧
- JS -- 棧有效圓括號
- JS -- 漢諾塔
- 結構 -- 隊列
- JS -- 隊列
- JS -- 雙端隊列
- JS -- 循環隊列
- 結構 -- 鏈表
- JS -- 鏈表
- JS -- 雙向鏈表
- JS -- 循環鏈表
- JS -- 有序鏈表
- 結構 -- JS 字典
- 結構 -- 散列表
- 結構 -- js 散列表
- 結構 -- js分離鏈表
- 結構 -- js開放尋址法
- 結構 -- 遞歸
- 結構 -- js遞歸經典問題
- 結構 -- 樹
- 結構 -- js 二搜索樹
- 結構 -- 紅黑樹
- 結構 -- 堆
- 結構 -- js 堆
- 結構 -- js 堆排序
- 結構 -- 排序
- js -- 冒泡排序
- js -- 選擇排序
- js -- 插入排序
- js -- 歸并排序
- js -- 快速排序
- js -- 計數排序
- js -- 桶排序
- js -- 基數排序
- 結構 -- 算法
- 搜索算法
- 二分搜索
- 內插搜索
- 隨機算法
- 簡單
- 第一題 兩數之和
- 第七題 反轉整數
- 第九題 回文數
- 第十三題 羅馬數字轉整數
- 常見一些需求
- 把原始 list 轉換成樹形結構