尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

【前端手撕】数组转树

【前端手撕】数组转树
📅 发布时间:2026/6/21 15:34:04

把平铺的数组结构转换为树结构。

const arr = [ { id: "01", name: "张大大", pid: "", job: "项目经理" }, { id: "02", name: "小亮", pid: "01", job: "产品leader" }, { id: "03", name: "小美", pid: "01", job: "UIleader" }, { id: "04", name: "老马", pid: "01", job: "技术leader" }, { id: "05", name: "老王", pid: "01", job: "测试leader" }, { id: "06", name: "老李", pid: "01", job: "运维leader" }, { id: "07", name: "小丽", pid: "02", job: "产品经理" }, { id: "08", name: "大光", pid: "02", job: "产品经理" }, { id: "09", name: "小高", pid: "03", job: "UI设计师" }, { id: "10", name: "小刘", pid: "04", job: "前端工程师" }, { id: "11", name: "小华", pid: "04", job: "后端工程师" }, { id: "12", name: "小李", pid: "04", job: "后端工程师" }, { id: "13", name: "小赵", pid: "05", job: "测试工程师" }, { id: "14", name: "小强", pid: "05", job: "测试工程师" }, { id: "15", name: "小涛", pid: "06", job: "运维工程师" }, ];

转换为:

[ { id: "01", name: "张大大", pid: "", job: "项目经理", children: [ { id: "02", name: "小亮", pid: "01", job: "产品leader", children: [ { id: "07", name: "小丽", pid: "02", job: "产品经理", children: [] }, { id: "08", name: "大光", pid: "02", job: "产品经理", children: [] } ] }, // ... 其他子节点 ] } ]

暴力递归

function toTree(list, parId = '') { let len = list.length function loop(parId) { let res = [] // 存当前层的所有子节点 // 递归遍历整个数组,找到当前层所有子节点(注意:每次都是遍历全部) for (let i = 0; i < len; i++) { if (list[i].pid === parId) { // 如果当前项的父id是parId,说明是当前层的子节点 // 递归调用loop函数,找到当前项的所有子节点 list[i].children = loop(list[i].id) // 把当前节点(带着它的children)放入结果 res.push(list[i]) } } return res } return loop(parId) }

因为每次递归都是遍历整个数组,所以时间复杂度是O(n²),数据量大的时候会很慢。

遍历数组其实是为了找到父节点对应的子节点,并进行组装。因此可以先用map来做一次映射,方便父子节点的快速定位和组装。优化为用哈希来解:

哈希解法

function toTreeHash(list) { const res = [] const map = {} // 先把所有项都放到哈希表中,浅拷贝不污染原数组 arr.forEach(item => map[item.id] = {...item, children:[]}) // 遍历数组,根据父id找到子节点,把子节点放到父节点的children数组中 for (let item of list) { let node = map[item.id] if (item.pid) { // 避免父节点不存在的情况导致报错 if (!map[item.pid]) continue // 把当前项放到父节点的children数组中 map[item.pid].children.push(node) } else { // 没有父id,说明是根节点 res.push(node) } } return res }

因为只遍历两次数组,时间复杂度为O(n)。

相关新闻

  • Betaflight Configurator终极指南:三步掌握无人机飞控调参核心技巧
  • 南京亨得利手表维修全攻略:从劳力士3235机芯保养到浪琴L888偷停修复,南京唯一官方售后网点深度探店与全品牌维修避坑指南——2026年6月紫峰大厦实地全记录 - 亨得利腕表维修中心
  • Photoshop图层批量导出终极指南:快速解决方案完整教程

最新新闻

  • 创业者国际EMBA理性测评与科学选型指南 - 品牌2026推荐
  • 2026 无锡市滨湖区防水、防水公司推荐|屋面防水、彩钢瓦翻新、钢结构修缮 TOP5 权威推荐 + 避坑指南(本地深度实操指南) - 速递信息
  • 影刀RPA新手入门:用RPA解放双手,从这5个日常场景开始
  • 2026 宣城防水、防水公司推荐|屋面防水、彩钢瓦翻新、钢结构修缮 TOP5 权威推荐 + 避坑指南(本地深度实操指南) - 速递信息
  • 嵌入式硬件探针实战:CodeTEST Probe接口配置与信号连接详解
  • 如何用pyannote.audio实现专业级说话人分割:从零开始的终极指南

日新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号