js中平级数组和树形结构数据相互转换
在实际的工作和业务需求中,我们经常会碰到树形数据结构,比如公司组织架构、组织层级、省市县或者事物的分类等等数据。那么在JavaScript中如何将数组转为树形结构和树形结构转为数组,本文就详细的来探究一下。
先来看看给出了一组怎样的数据,转换为怎样的树形结构。
后台接口返回或者面试官给你的数据:const list = [ {id: 1, name: "部门1", pid: 0}, {id: 2, name: "部门1-1", pid: 1}, {id: 3, name: "部门1-2", pid: 1}, {id: 4, name: "部门1-1-1", pid: 2}, {id: 5, name: "部门1-2-1", pid: 3}, {id: 6, name: "部门2", pid: 0}, {id: 7, name: "部门2-1", pid: 6}, {id: 8, name: "部门3", pid: 0}, ]
期望的处理后的数据:const listTree = [ { id: 1, name: "部门1", pid: 0, children: [ { id: 2, name: "部门1-1", pid: 1, children: [ { id: 4, name: "部门1-1-1", pid: 2, children: [] } ] }, { id: 3, name: "部门1-2", pid: 1, children: [ { id: 5, name: "部门1-2-1", pid: 3, children: [] } ] } ] }, { id: 6, name: "部门2", pid: 0, children: [ { id: 7, name: "部门2-1", pid: 6, children: [] } ] }, { id: 8, name: "部门3", pid: 0, children: [] } ]
一、数组转换为树形结构
如果后台给了一个这样的数据说让前端自己去转换为树形结构或者面试官给你一组这样的数据让你手写一个转换方法,你会怎么处理?
1、递归实现// 递归查找获取子节点 const getChild = (list, result, pid) => { for(const item of list) { if(item.pid === pid) { const newItem = { ...item, children: [] }; result.push(newItem); getChild(list, newItem.children, item.id); } } } // 调用递归实现 const listToTree = (list, pid) => { const result = []; getChild(list, result, pid); return result; } listToTree(list, 0)
2、Map对象实现const listToTree = (list) => { // 最终树形结构输出的结果 const result = []; const itemMap = {}; for(const item of list) { const id = item.id; const pid = item.pid; if(!itemMap[id]) { itemMap[id] = { children: [], }; } itemMap[id] = { ...item, children: itemMap[id]["children"], }; const treeItem = itemMap[id]; if(pid === 0) { result.push(treeItem) } else { if(!itemMap[pid]) { itemMap[pid] = { children: [] } } itemMap[pid].children.push(treeItem); } } return result; } listToTree(list, 0)
3、filter实现
这种方法很有意思,可能大多数人想不到,也是从大佬处学到的(读书人的是怎么能叫抄呢,应该叫"窃")。const listToTree = (list, key) => { const tree = list.filter(function(parent) { // 返回每一项得的子级数据 const branchArr = list.filter((child) => parent.id === child[key]); parent.children = []; // 如果存在子级,则给父级添加一个children属性并赋值 if (branchArr.length > 0) { parent.children = branchArr; } // 返回第一层 return parent[key] == 0; }); return tree; } // 传入原始数据和父级pid的key listToTree(list, "pid")
二、树形结构转换为数组
1、reduce取树行数据的所有子集function treeTransList(tree, key) { return tree.reduce(function(con, item) { var callee = arguments.callee; con.push(item); if (item[key] && item[key].length >0) item[key].reduce(callee, con); return con; }, []).map(function(item){ item[key] = []; return item; }) } treeTransList(listTree, "children")
2、递归实现function getItem(tree, result) { for (let i = 0; i < tree.length; i++) { if(tree[i].children) { getItem(tree[i].children, result) delete tree[i].children; } result.push(tree[i]) } return result; } function treeToList(tree) { const result = []; getItem(tree, result); return result; } treeToList(listTree)
3、广度优先遍历法function treeToList(tree, childName = "children") { // 设置临时数组,用来存放队列 let queen = []; // 设置输出数组,用来存放要输出的一维数组 const result = []; queen = queen.concat(tree); // 对树对象进行广度优先的遍历 while(queen.length) { const first = queen.shift(); if (first[childName]) { queen = queen.concat(first[childName]); delete first[childName] } result.push(first); } return result; } treeToList(listTree, "children")