JavaScript 實現(xiàn)普通數(shù)組數(shù)據(jù)轉化為樹形數(shù)據(jù)結構的步驟說明
在 JavaScript 中,將普通數(shù)組數(shù)據(jù)轉化為樹形結構的數(shù)據(jù)是一個常見的任務,特別是在處理層級數(shù)據(jù)(例如分類、組織結構等)時。下面是一個詳細的步驟說明,展示如何將一個扁平的數(shù)組轉化為樹形數(shù)據(jù)結構。
示例數(shù)據(jù)
假設我們有以下的扁平數(shù)組,每個元素代表一個節(jié)點,并且每個節(jié)點包含一個 id 和一個 parentId,parentId 用于表示父節(jié)點的關系:
const data = [
{ id: 1, name: 'Root', parentId: null },
{ id: 2, name: 'Child 1', parentId: 1 },
{ id: 3, name: 'Child 2', parentId: 1 },
{ id: 4, name: 'Grandchild 1', parentId: 2 },
{ id: 5, name: 'Grandchild 2', parentId: 2 },
];目標
將上述數(shù)據(jù)轉化為以下樹形結構:
[
{
id: 1,
name: 'Root',
children: [
{
id: 2,
name: 'Child 1',
children: [
{ id: 4, name: 'Grandchild 1', children: [] },
{ id: 5, name: 'Grandchild 2', children: [] }
]
},
{
id: 3,
name: 'Child 2',
children: []
}
]
}
]實現(xiàn)步驟
創(chuàng)建一個空對象來存儲每個節(jié)點的引用:
const nodeMap = {};遍歷數(shù)組,初始化節(jié)點并填充 nodeMap:
data.forEach(item => {
nodeMap[item.id] = { ...item, children: [] };
});這樣每個節(jié)點都被映射到 nodeMap 中,并且每個節(jié)點都有一個 children 屬性用于存儲子節(jié)點。
遍歷數(shù)組,將每個節(jié)點添加到其父節(jié)點的 children 中:
data.forEach(item => {
if (item.parentId) {
// 如果節(jié)點有父節(jié)點,將其添加到父節(jié)點的 children 中
const parent = nodeMap[item.parentId];
if (parent) {
parent.children.push(nodeMap[item.id]);
}
}
});提取根節(jié)點:
根節(jié)點是 parentId 為 null 的節(jié)點。我們可以從 nodeMap 中找出這些節(jié)點。
const tree = Object.values(nodeMap).filter(node => node.parentId === null);
完整代碼示例
以下是將上述步驟整合在一起的完整代碼:
const data = [
{ id: 1, name: 'Root', parentId: null },
{ id: 2, name: 'Child 1', parentId: 1 },
{ id: 3, name: 'Child 2', parentId: 1 },
{ id: 4, name: 'Grandchild 1', parentId: 2 },
{ id: 5, name: 'Grandchild 2', parentId: 2 },
];
function buildTree(data) {
const nodeMap = {};
// 初始化 nodeMap
data.forEach(item => {
nodeMap[item.id] = { ...item, children: [] };
});
// 構建樹形結構
data.forEach(item => {
if (item.parentId) {
const parent = nodeMap[item.parentId];
if (parent) {
parent.children.push(nodeMap[item.id]);
}
}
});
// 提取根節(jié)點
return Object.values(nodeMap).filter(node => node.parentId === null);
}
const tree = buildTree(data);
console.log(JSON.stringify(tree, null, 2));解釋
初始化節(jié)點映射:
nodeMap 用于存儲每個節(jié)點的引用,并初始化每個節(jié)點的 children 為空數(shù)組。
建立父子關系:
遍歷數(shù)據(jù),找到每個節(jié)點的父節(jié)點,并將當前節(jié)點添加到父節(jié)點的 children 中。
提取根節(jié)點:
通過過濾 nodeMap 中 parentId 為 null 的節(jié)點,得到樹的根節(jié)點。
遞歸函數(shù)實現(xiàn)
function buildTree(flatData, parentId = null) {
return flatData
.filter(node => node.parentId === parentId)
.map(node => ({
...node,
children: buildTree(flatData, node.id)
}));
}參數(shù)說明
flatData: 扁平的數(shù)組數(shù)據(jù)。每個元素包含id和parentId,用于表示節(jié)點和它們的父節(jié)點關系。parentId: 當前要處理的父節(jié)點的 ID。默認為null,表示初始調用時的根節(jié)點。
函數(shù)實現(xiàn)細節(jié)
過濾節(jié)點:
flatData.filter(node => node.parentId === parentId)
filter方法會返回flatData中所有parentId等于當前parentId的節(jié)點。這意味著我們在尋找所有直接子節(jié)點。- 初次調用時,
parentId是null,所以我們得到的是所有根節(jié)點。
映射節(jié)點:
.map(node => ({
...node,
children: buildTree(flatData, node.id)
}))map方法對過濾后的每個節(jié)點執(zhí)行回調函數(shù)。- 回調函數(shù)的目的是將當前節(jié)點的
children屬性設置為一個遞歸調用buildTree函數(shù)的結果。
遞歸調用:
buildTree(flatData, node.id)
- 對于每個節(jié)點,我們再次調用
buildTree函數(shù),將當前節(jié)點的id作為新的parentId。 - 這會找到當前節(jié)點的所有子節(jié)點,并將這些子節(jié)點作為當前節(jié)點的
children屬性。
遞歸過程
初始調用:
buildTree(flatData)
第一次調用時 parentId 是 null,這意味著我們查找所有根節(jié)點。
查找子節(jié)點:
對于每一個根節(jié)點,buildTree 會被調用,查找該節(jié)點的直接子節(jié)點。
逐級遞歸:
對每個子節(jié)點,buildTree 會遞歸調用自身,繼續(xù)查找該子節(jié)點的子節(jié)點,直到所有節(jié)點的 children 屬性都被填充。
示例
假設我們有以下扁平數(shù)據(jù):
const data = [
{ id: 1, name: 'Root', parentId: null },
{ id: 2, name: 'Child 1', parentId: 1 },
{ id: 3, name: 'Child 2', parentId: 1 },
{ id: 4, name: 'Grandchild 1', parentId: 2 },
{ id: 5, name: 'Grandchild 2', parentId: 2 }
];調用 buildTree(data) 時:
第一層:
parentId 是 null,找到 ID 為 1 的根節(jié)點。
第二層:
對于根節(jié)點(ID 為 1),調用 buildTree(data, 1) 查找其子節(jié)點,找到 ID 為 2 和 3 的節(jié)點。
第三層:
對于 ID 為 2 的節(jié)點,調用 buildTree(data, 2) 查找其子節(jié)點,找到 ID 為 4 和 5 的節(jié)點。
第四層:
ID 為 4 和 5 的節(jié)點沒有子節(jié)點,所以遞歸終止,返回空的 children 數(shù)組。
最終得到的樹形數(shù)據(jù)結構如下:
[
{
id: 1,
name: 'Root',
children: [
{
id: 2,
name: 'Child 1',
children: [
{ id: 4, name: 'Grandchild 1', children: [] },
{ id: 5, name: 'Grandchild 2', children: [] }
]
},
{
id: 3,
name: 'Child 2',
children: []
}
]
}
]總結
這個 buildTree 函數(shù)使用了遞歸的方式來構建樹形數(shù)據(jù)結構。通過過濾、映射和遞歸調用,它逐層構建每個節(jié)點的子節(jié)點,直到所有節(jié)點的 children 屬性都被正確填充。這種方法簡潔且高效,適合處理層級數(shù)據(jù)。
到此這篇關于JavaScript 實現(xiàn)普通數(shù)組數(shù)據(jù)轉化為樹形數(shù)據(jù)結構的文章就介紹到這了,更多相關js普通數(shù)組轉化樹形結構內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
微信小程序BindTap快速連續(xù)點擊目標頁面跳轉多次問題處理
這篇文章主要介紹了微信小程序BindTap快速連續(xù)點擊目標頁面跳轉多次問題處理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04
layui 中select下拉change事件失效的解決方法
今天小編就為大家分享一篇layui 中select下拉change事件失效的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-09-09

