扁平化数据与树状数据
在开发过程中,前后端数据交互时后端同事为了省时省力,会直接把从数据库查出的扁平化数据不经格式处理直接在接口中返给前端,例如以下数据:
let arr= [
{ id: 1, parent_id: 'root', name: 'name1' },
{ id: '2-1', parent_id: 2, name: 'name2' },
{ id: '4-1', parent_id: 4, name: 'name3' },
{ id: '2-2', parent_id: 2, name: 'name4' },
{ id: '3-2', parent_id: 3, name: 'name5' },
{ id: '3-1', parent_id: 3, name: 'name6' },
{ id: '1-1', parent_id: 1, name: 'name6' },
{ id: 2, parent_id: 'root', name: 'name7' },
{ id: 3, parent_id: 'root', name: 'name8' },
{ id: 4, parent_id: 'root', name: 'name9' },
{ id: '3-2-1', parent_id: '3-2', name: 'name9' }
]
这是一个数组列表,没有层级结构所以是扁平化的。我们需要转换成树状结构的数据,首先要分析列表每一项中有关联的字段,按照字面意思就能看出来,id在每一项中都是唯一的,parent_id就是该项指向的父级,一旦出现子级与父级那么层级结构就出来了,root就是根级可以理解为第一级;分析以后那么我们想要的树状数据就可以整理出来:
{
"1":{
"id":1,
"parent_id":"root",
"name":"name1",
"children":[
{
"id":"1-1",
"parent_id":1,
"name":"name6"
}]
},
"2":{
"id":2,
"parent_id":"root",
"name":"name7",
"children":[
{
"id":"2-1",
"parent_id":2,
"name":"name2"
},
{
"id":"2-2",
"parent_id":2,
"name":"name4"
}]
},
"3":{
"id":3,
"parent_id":"root",
"name":"name8",
"children":[
{
"id":"3-2",
"parent_id":3,
"name":"name5",
"children":[
{
"id":"3-2-1",
"parent_id":"3-2",
"name":"name9"
}]
},
{
"id":"3-1",
"parent_id":3,
"name":"name6"
}]
},
"4":{
"id":4,
"parent_id":"root",
"name":"name9",
"children":[
{
"id":"4-1",
"parent_id":4,
"name":"name3"
}]
}
}
扁平化结构转树状结构
创建一个临时空对象temp来暂存数组列表,使对象中每一对键值对的键对应为列表中每一项的id,那么值就是列表项本身,如: { id: 1, parent_id: 'root', name: 'name1' }=>{"1":{ id: 1, parent_id: 'root', name: 'name1' }},暂存以后遍历temp,使子级与父级建立联系,父级在前子级在后,父级存在子级的时候建立children对象存储子级,如此循环:
function toTree(array, id, parent_id) {
// 创建临时对象
let temp = {};
// 创建需要返回的树形对象
let tree = {};
// 先遍历数组,将数组的每一项添加到temp对象中
for (let i in array) {
temp[array[i][id]] = array[i];
}
// 遍历temp对象,将当前子节点与父节点建立连接
for (let i in temp) {
// 判断是否是根节点下的项
if (temp[i][parent_id] !== 'root') {
if (!temp[temp[i][parent_id]].children) {
temp[temp[i][parent_id]].children = new Array();
}
temp[temp[i][parent_id]].children.push(temp[i]);
} else {
tree[temp[i][id]] = temp[i];
}
}
/* 上面for let遍历也可以写成
for(let i=0;i<array.length;i++) {
temp[array[i][id]] = array[i];
}
*/
return tree;
}
const res = toTree(arr, 'id', 'parent_id');
for(let i in array) 可以写成 for(let i=0;i<array.length;i++) 这种循环写法,前者更好,因为当数据量过大的时候,后者写法就会很占用资源导致执行时间久,前面一种写法速度就会很快;
树状转扁平化
树状结构转扁平化结构在前端应用场景较少,直接贴出代码
function tree2Array(treeObj, rootid) {
const temp = []; // 设置临时数组,用来存放队列
const out = []; // 设置输出数组,用来存放要输出的一维数组
temp.push(treeObj);
// 首先把根元素存放入out中
let pid = rootid;
const obj = deepCopy(treeObj);
obj.pid = pid;
delete obj['children'];
out.push(obj)
// 对树对象进行广度优先的遍历
while(temp.length > 0) {
const first = temp.shift();
const children = first.children;
if(children && children.length > 0) {
pid = first.id;
const len = first.children.length;
for(let i=0;i<len;i++) {
temp.push(children[i]);
const obj = deepCopy(children[i]);
obj.pid = pid;
delete obj['children'];
out.push(obj)
}
}
}
return out
}