最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用JavaScript將扁平數(shù)據(jù)轉(zhuǎn)換為樹形結(jié)構(gòu)的多種實現(xiàn)方法

 更新時間:2025年04月30日 08:41:35   作者:北辰alk  
在實際開發(fā)中,我們經(jīng)常需要將扁平的數(shù)據(jù)結(jié)構(gòu)(如數(shù)據(jù)庫查詢結(jié)果)轉(zhuǎn)換為樹形結(jié)構(gòu)(如菜單、評論回復(fù)等),本文將詳細介紹多種實現(xiàn)方法,并提供完整的代碼示例,需要的朋友可以參考下

一、理解數(shù)據(jù)結(jié)構(gòu)

1. 扁平數(shù)據(jù)結(jié)構(gòu)示例

const flatData = [
  { id: 1, name: '部門1', parentId: 0 },
  { id: 2, name: '部門2', parentId: 1 },
  { id: 3, name: '部門3', parentId: 1 },
  { id: 4, name: '部門4', parentId: 3 },
  { id: 5, name: '部門5', parentId: 3 },
  { id: 6, name: '部門6', parentId: 0 },
];

2. 期望的樹形結(jié)構(gòu)

[
  {
    id: 1,
    name: '部門1',
    children: [
      {
        id: 2,
        name: '部門2'
      },
      {
        id: 3,
        name: '部門3',
        children: [
          { id: 4, name: '部門4' },
          { id: 5, name: '部門5' }
        ]
      }
    ]
  },
  {
    id: 6,
    name: '部門6'
  }
]

二、實現(xiàn)方法

方法1:遞歸實現(xiàn)(經(jīng)典算法)

function buildTree(items, parentId = 0) {
  const result = [];
  
  for (const item of items) {
    if (item.parentId === parentId) {
      const children = buildTree(items, item.id);
      if (children.length) {
        item.children = children;
      }
      result.push(item);
    }
  }
  
  return result;
}

const treeData = buildTree(flatData);
console.log(JSON.stringify(treeData, null, 2));

優(yōu)點

  • 邏輯清晰直觀
  • 適合理解樹形結(jié)構(gòu)的構(gòu)建過程

缺點

  • 時間復(fù)雜度較高(O(n^2))
  • 大數(shù)據(jù)量時性能較差

方法2:使用對象引用(高效算法)

function buildTreeOptimized(items) {
  const itemMap = {};
  const result = [];
  
  // 首先構(gòu)建哈希映射
  for (const item of items) {
    itemMap[item.id] = { ...item, children: [] };
  }
  
  // 構(gòu)建樹結(jié)構(gòu)
  for (const item of items) {
    const node = itemMap[item.id];
    if (item.parentId === 0) {
      result.push(node);
    } else {
      if (itemMap[item.parentId]) {
        itemMap[item.parentId].children.push(node);
      }
    }
  }
  
  return result;
}

const optimizedTree = buildTreeOptimized(flatData);
console.log(JSON.stringify(optimizedTree, null, 2));

優(yōu)點

  • 時間復(fù)雜度O(n),性能優(yōu)異
  • 適合大數(shù)據(jù)量處理

缺點

  • 需要額外的內(nèi)存空間存儲映射

方法3:使用Map數(shù)據(jù)結(jié)構(gòu)(ES6+)

function buildTreeWithMap(items) {
  const map = new Map();
  const result = [];
  
  // 初始化所有節(jié)點并存入Map
  items.forEach(item => {
    map.set(item.id, { ...item, children: [] });
  });
  
  // 構(gòu)建樹結(jié)構(gòu)
  items.forEach(item => {
    const node = map.get(item.id);
    if (item.parentId === 0) {
      result.push(node);
    } else {
      const parent = map.get(item.parentId);
      if (parent) {
        parent.children.push(node);
      }
    }
  });
  
  return result;
}

const mapTree = buildTreeWithMap(flatData);
console.log(JSON.stringify(mapTree, null, 2));

優(yōu)點

  • 使用Map更現(xiàn)代,性能更好
  • 支持任意類型作為鍵

方法4:使用reduce實現(xiàn)(函數(shù)式編程)

function buildTreeWithReduce(items) {
  const itemMap = items.reduce((map, item) => {
    map[item.id] = { ...item, children: [] };
    return map;
  }, {});
  
  return items.reduce((result, item) => {
    if (item.parentId === 0) {
      result.push(itemMap[item.id]);
    } else if (itemMap[item.parentId]) {
      itemMap[item.parentId].children.push(itemMap[item.id]);
    }
    return result;
  }, []);
}

const reducedTree = buildTreeWithReduce(flatData);
console.log(JSON.stringify(reducedTree, null, 2));

優(yōu)點

  • 函數(shù)式風(fēng)格,代碼簡潔
  • 兩次遍歷完成構(gòu)建

三、進階功能實現(xiàn)

1. 添加排序功能

function buildTreeWithSort(items, sortBy = 'id') {
  const itemMap = {};
  const result = [];
  
  // 構(gòu)建映射
  items.forEach(item => {
    itemMap[item.id] = { ...item, children: [] };
  });
  
  // 構(gòu)建樹結(jié)構(gòu)
  items.forEach(item => {
    const node = itemMap[item.id];
    if (item.parentId === 0) {
      result.push(node);
    } else if (itemMap[item.parentId]) {
      itemMap[item.parentId].children.push(node);
    }
  });
  
  // 遞歸排序
  function sortTree(nodes) {
    nodes.sort((a, b) => a[sortBy] - b[sortBy]);
    nodes.forEach(node => {
      if (node.children.length) {
        sortTree(node.children);
      }
    });
  }
  
  sortTree(result);
  return result;
}

const sortedTree = buildTreeWithSort(flatData, 'id');
console.log(JSON.stringify(sortedTree, null, 2));

2. 處理循環(huán)引用

function buildTreeWithCycleDetection(items) {
  const itemMap = {};
  const result = [];
  const visited = new Set();
  
  // 構(gòu)建映射
  items.forEach(item => {
    itemMap[item.id] = { ...item, children: [] };
  });
  
  // 檢測循環(huán)引用
  function hasCycle(node, parentIds = new Set()) {
    if (parentIds.has(node.id)) return true;
    parentIds.add(node.id);
    
    for (const child of node.children) {
      if (hasCycle(child, new Set(parentIds))) {
        return true;
      }
    }
    
    return false;
  }
  
  // 構(gòu)建樹結(jié)構(gòu)
  items.forEach(item => {
    if (!visited.has(item.id)) {
      const node = itemMap[item.id];
      if (item.parentId === 0) {
        result.push(node);
      } else if (itemMap[item.parentId]) {
        itemMap[item.parentId].children.push(node);
      }
      visited.add(item.id);
      
      // 檢查循環(huán)引用
      if (hasCycle(node)) {
        throw new Error(`檢測到循環(huán)引用,節(jié)點ID: ${node.id}`);
      }
    }
  });
  
  return result;
}

3. 支持自定義子節(jié)點字段名

function buildTreeCustomChildren(items, childrenField = 'children') {
  const itemMap = {};
  const result = [];
  
  // 構(gòu)建映射
  items.forEach(item => {
    itemMap[item.id] = { ...item, [childrenField]: [] };
  });
  
  // 構(gòu)建樹結(jié)構(gòu)
  items.forEach(item => {
    const node = itemMap[item.id];
    if (item.parentId === 0) {
      result.push(node);
    } else if (itemMap[item.parentId]) {
      itemMap[item.parentId][childrenField].push(node);
    }
  });
  
  return result;
}

四、性能優(yōu)化技巧

  • 使用Map代替普通對象:當(dāng)ID為非數(shù)字時性能更好
  • 批量處理數(shù)據(jù):對于大數(shù)據(jù)量可分批次處理
  • 使用Web Worker:對于極大數(shù)據(jù)集可在后臺線程處理
  • 惰性加載:只構(gòu)建和渲染可見部分的樹結(jié)構(gòu)

五、實際應(yīng)用示例

1. 渲染樹形菜單(React示例)

function TreeMenu({ data }) {
  return (
    <ul>
      {data.map(node => (
        <li key={node.id}>
          {node.name}
          {node.children && node.children.length > 0 && (
            <TreeMenu data={node.children} />
          )}
        </li>
      ))}
    </ul>
  );
}

// 使用
const treeData = buildTreeOptimized(flatData);
ReactDOM.render(<TreeMenu data={treeData} />, document.getElementById('root'));

2. 樹形表格(Vue示例)

<template>
  <table>
    <tbody>
      <tree-row 
        v-for="node in treeData" 
        :key="node.id" 
        :node="node"
        :level="0"
      />
    </tbody>
  </table>
</template>

<script>
import { buildTreeWithMap } from './treeUtils';

export default {
  data() {
    return {
      flatData: [...], // 原始扁平數(shù)據(jù)
      treeData: []
    };
  },
  created() {
    this.treeData = buildTreeWithMap(this.flatData);
  },
  components: {
    TreeRow: {
      props: ['node', 'level'],
      template: `
        <tr :style="{ paddingLeft: level * 20 + 'px' }">
          <td>{{ node.name }}</td>
          <td>{{ node.otherField }}</td>
        </tr>
        <tree-row 
          v-for="child in node.children" 
          :key="child.id" 
          :node="child"
          :level="level + 1"
          v-if="node.children"
        />
      `
    }
  }
};
</script>

六、總結(jié)與最佳實踐

  1. 選擇合適算法

    • 小數(shù)據(jù)量:遞歸算法簡單直觀
    • 大數(shù)據(jù)量:對象引用或Map實現(xiàn)性能更好
  2. 處理邊界情況

    • 無效的parentId引用
    • 循環(huán)引用檢測
    • 重復(fù)數(shù)據(jù)處理
  3. 擴展性考慮

    • 支持自定義子節(jié)點字段名
    • 添加排序功能
    • 支持異步數(shù)據(jù)加載
  4. 性能監(jiān)控

    • 對于超大數(shù)據(jù)集考慮分頁或虛擬滾動
    • 使用性能分析工具監(jiān)控構(gòu)建時間
  5. 測試建議

// 單元測試示例
describe('樹形結(jié)構(gòu)構(gòu)建', () => {
  it('應(yīng)正確構(gòu)建樹形結(jié)構(gòu)', () => {
    const flatData = [...];
    const treeData = buildTreeOptimized(flatData);
    expect(treeData.length).toBe(2);
    expect(treeData[0].children.length).toBe(2);
    expect(treeData[0].children[1].children.length).toBe(2);
  });
  
  it('應(yīng)處理無效parentId', () => {
    const invalidData = [...];
    const treeData = buildTreeOptimized(invalidData);
    expect(treeData.length).toBe(1);
  });
});

通過本文介紹的各種方法和技巧,您應(yīng)該能夠根據(jù)實際需求選擇最適合的方式將扁平數(shù)據(jù)轉(zhuǎn)換為樹形結(jié)構(gòu)。在實際項目中,推薦使用對象引用或Map實現(xiàn)的高效算法,它們在大數(shù)據(jù)量下表現(xiàn)優(yōu)異,同時代碼也相對清晰可維護。

以上就是使用JavaScript將扁平數(shù)據(jù)轉(zhuǎn)換為樹形結(jié)構(gòu)的多種實現(xiàn)方法的詳細內(nèi)容,更多關(guān)于JavaScript扁平數(shù)據(jù)轉(zhuǎn)樹形結(jié)構(gòu)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JS調(diào)用打印方法設(shè)置頁眉頁腳的實例

    JS調(diào)用打印方法設(shè)置頁眉頁腳的實例

    一個網(wǎng)頁打印相關(guān)功能的擴展演示特效,在實現(xiàn)了打印功能外,還實現(xiàn)了打印預(yù)覽、打印前的頁眉頁腳設(shè)置,直接打印等功能,以前對JS打印前設(shè)置頁腳見的不多,所以這一個也算是挺有價值的,希望閑暇時參閱
    2013-05-05
  • JavaScript中為元素加上name屬性的方法

    JavaScript中為元素加上name屬性的方法

    干前端這行當(dāng)已經(jīng)超過一個月了, 每天都會遇到新奇古怪, 甚至離奇的問題. 雖然絕大部分都是一些小問題, 但我覺得還是有必要記錄下來
    2011-05-05
  • ESC之ESC.wsf可以實現(xiàn)javascript的代碼壓縮附使用方法

    ESC之ESC.wsf可以實現(xiàn)javascript的代碼壓縮附使用方法

    可以對javascript的大小進行壓縮。使javascript的加載速度變快。
    2007-05-05
  • 前端給后端傳數(shù)據(jù)的五種方式總結(jié)

    前端給后端傳數(shù)據(jù)的五種方式總結(jié)

    前端與后端數(shù)據(jù)交互是軟件開發(fā)中不可或缺的一環(huán),下面這篇文章主要給大家介紹了關(guān)于前端給后端傳數(shù)據(jù)的五種方式,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-07-07
  • javascript瀏覽器用戶代理檢測腳本實現(xiàn)方法

    javascript瀏覽器用戶代理檢測腳本實現(xiàn)方法

    下面小編就為大家?guī)硪黄猨avascript瀏覽器用戶代理檢測腳本實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • js中script的上下放置區(qū)別,Dom的增刪改創(chuàng)建操作實例分析

    js中script的上下放置區(qū)別,Dom的增刪改創(chuàng)建操作實例分析

    這篇文章主要介紹了js中script的上下放置區(qū)別,Dom的增刪改創(chuàng)建操作,結(jié)合實例形式分析了JavaScript基本dom事件、script在head和body中放置的區(qū)別、以及Dom的增刪改創(chuàng)建等相關(guān)操作技巧,需要的朋友可以參考下
    2019-12-12
  • JavaScript實現(xiàn)深拷貝的不同方法匯總

    JavaScript實現(xiàn)深拷貝的不同方法匯總

    在JavaScript中,我們經(jīng)常需要將一個對象的所有數(shù)據(jù)復(fù)制到另一個對象中,這種操作可以分為 淺拷貝 和 深拷貝,而深拷貝則是指完全復(fù)制一個對象及其所有嵌套的對象,而不僅僅是對象的引用,本文,我們將深入探討深拷貝的概念,以及如何使用不同的方法實現(xiàn)深拷貝
    2025-06-06
  • hash特點、hashchange事件介紹及其常見應(yīng)用場景

    hash特點、hashchange事件介紹及其常見應(yīng)用場景

    淺析hash特點、hashchange事件介紹及其常見應(yīng)用場景(不同hash對應(yīng)不同事件處理、移動端大圖展示狀態(tài)后退頁面問題、原生輕應(yīng)用頭部后退問題、移動端自帶返回按鈕二次確認問題),hashchange和popstate事件觸發(fā)條件
    2023-11-11
  • 一文總結(jié)JS中邏輯運算符的特點

    一文總結(jié)JS中邏輯運算符的特點

    在JavaScript的眾多運算符里,提供了三個邏輯運算符&&、||和!,下面這篇文章主要給大家介紹了關(guān)于JS中邏輯運算符的特點,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-03-03
  • layui使用button按鈕 點擊出現(xiàn)彈層 彈層中加載表單的實例

    layui使用button按鈕 點擊出現(xiàn)彈層 彈層中加載表單的實例

    今天小編就為大家分享一篇layui使用button按鈕 點擊出現(xiàn)彈層 彈層中加載表單的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-09-09

最新評論

边坝县| 淳化县| 齐齐哈尔市| 保亭| 昭平县| 临海市| 嘉定区| 闸北区| 赣州市| 德令哈市| 寿光市| 仁化县| 保山市| 青海省| 富裕县| 宁海县| 文登市| 深圳市| 沙洋县| 乌海市| 马尔康县| 民勤县| 银川市| 诏安县| 潜山县| 哈尔滨市| 合江县| 偏关县| 永宁县| 溧阳市| 开阳县| 互助| 三原县| 黄浦区| 曲阜市| 凉城县| 大田县| 河东区| 朝阳市| 白河县| 通道|