欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript 實現(xiàn)普通數(shù)組數(shù)據(jù)轉(zhuǎn)化為樹形數(shù)據(jù)結(jié)構(gòu)的步驟說明

 更新時間:2024年12月13日 11:32:25   作者:跳房子的前端  
在 JavaScript 中,將普通數(shù)組數(shù)據(jù)轉(zhuǎn)化為樹形結(jié)構(gòu)的數(shù)據(jù)是一個常見的任務(wù),特別是在處理層級數(shù)據(jù)(例如分類、組織結(jié)構(gòu)等)時,本文展示如何將一個扁平的數(shù)組轉(zhuǎn)化為樹形數(shù)據(jù)結(jié)構(gòu),感興趣的朋友一起看看吧

在 JavaScript 中,將普通數(shù)組數(shù)據(jù)轉(zhuǎn)化為樹形結(jié)構(gòu)的數(shù)據(jù)是一個常見的任務(wù),特別是在處理層級數(shù)據(jù)(例如分類、組織結(jié)構(gòu)等)時。下面是一個詳細(xì)的步驟說明,展示如何將一個扁平的數(shù)組轉(zhuǎn)化為樹形數(shù)據(jù)結(jié)構(gòu)。

示例數(shù)據(jù)

假設(shè)我們有以下的扁平數(shù)組,每個元素代表一個節(jié)點,并且每個節(jié)點包含一個 id 和一個 parentIdparentId 用于表示父節(jié)點的關(guān)系:

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 },
];

目標(biāo)

將上述數(shù)據(jù)轉(zhuǎn)化為以下樹形結(jié)構(gòu):

[
  {
    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é)點是 parentIdnull 的節(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: [] };
  });
  // 構(gòu)建樹形結(jié)構(gòu)
  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ù)組。

建立父子關(guān)系

遍歷數(shù)據(jù),找到每個節(jié)點的父節(jié)點,并將當(dāng)前節(jié)點添加到父節(jié)點的 children 中。

提取根節(jié)點

通過過濾 nodeMapparentIdnull 的節(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ù)。每個元素包含 idparentId,用于表示節(jié)點和它們的父節(jié)點關(guān)系。
  • parentId: 當(dāng)前要處理的父節(jié)點的 ID。默認(rèn)為 null,表示初始調(diào)用時的根節(jié)點。

函數(shù)實現(xiàn)細(xì)節(jié)

過濾節(jié)點

flatData.filter(node => node.parentId === parentId)
  • filter 方法會返回 flatData 中所有 parentId 等于當(dāng)前 parentId 的節(jié)點。這意味著我們在尋找所有直接子節(jié)點。
  • 初次調(diào)用時,parentIdnull,所以我們得到的是所有根節(jié)點。

映射節(jié)點

.map(node => ({
  ...node,
  children: buildTree(flatData, node.id)
}))
  • map 方法對過濾后的每個節(jié)點執(zhí)行回調(diào)函數(shù)。
  • 回調(diào)函數(shù)的目的是將當(dāng)前節(jié)點的 children 屬性設(shè)置為一個遞歸調(diào)用 buildTree 函數(shù)的結(jié)果。

遞歸調(diào)用

buildTree(flatData, node.id)
  • 對于每個節(jié)點,我們再次調(diào)用 buildTree 函數(shù),將當(dāng)前節(jié)點的 id 作為新的 parentId。
  • 這會找到當(dāng)前節(jié)點的所有子節(jié)點,并將這些子節(jié)點作為當(dāng)前節(jié)點的 children 屬性。

遞歸過程

初始調(diào)用

buildTree(flatData)

第一次調(diào)用時 parentIdnull,這意味著我們查找所有根節(jié)點。

查找子節(jié)點

對于每一個根節(jié)點,buildTree 會被調(diào)用,查找該節(jié)點的直接子節(jié)點。

逐級遞歸

對每個子節(jié)點,buildTree 會遞歸調(diào)用自身,繼續(xù)查找該子節(jié)點的子節(jié)點,直到所有節(jié)點的 children 屬性都被填充。

示例

假設(shè)我們有以下扁平數(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 }
];

調(diào)用 buildTree(data) 時:

第一層

parentIdnull,找到 ID 為 1 的根節(jié)點。

第二層

對于根節(jié)點(ID 為 1),調(diào)用 buildTree(data, 1) 查找其子節(jié)點,找到 ID 為 23 的節(jié)點。

第三層

對于 ID 為 2 的節(jié)點,調(diào)用 buildTree(data, 2) 查找其子節(jié)點,找到 ID 為 45 的節(jié)點。

第四層

ID 為 45 的節(jié)點沒有子節(jié)點,所以遞歸終止,返回空的 children 數(shù)組。

最終得到的樹形數(shù)據(jù)結(jié)構(gòu)如下:

[
  {
    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: []
      }
    ]
  }
]

總結(jié)

這個 buildTree 函數(shù)使用了遞歸的方式來構(gòu)建樹形數(shù)據(jù)結(jié)構(gòu)。通過過濾、映射和遞歸調(diào)用,它逐層構(gòu)建每個節(jié)點的子節(jié)點,直到所有節(jié)點的 children 屬性都被正確填充。這種方法簡潔且高效,適合處理層級數(shù)據(jù)。

到此這篇關(guān)于JavaScript 實現(xiàn)普通數(shù)組數(shù)據(jù)轉(zhuǎn)化為樹形數(shù)據(jù)結(jié)構(gòu)的文章就介紹到這了,更多相關(guān)js普通數(shù)組轉(zhuǎn)化樹形結(jié)構(gòu)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論