前言
在进行业务开发的时候常遇到需要通过数组元素间的关系构造一颗树,功能我想大家都能实现,但代码的简洁性、可读性、性能等都是要考虑的因素。
代码和小栗子
原数组:
/*
* id: 当前元素的唯一标识
* pid: 当前元素的父元素的唯一标识
* otherData: 当前元素的其他数据
*/
let list = [
{
id: 'a',
pid: 'b',
otherData: {}
},{
id: 'b',
pid: null,
otherData: {}
},{
id: 'c',
pid: 'a',
otherData: {}
},{
id: 'd',
pid: 'a',
otherData: {}
},{
id: 'e',
pid: 'b',
otherData: {}
}
]
方法一:
// 这是遍历构建树的方案,时间复杂度稳定为O(N²)
const ROOR_PID = null;
export default class Model {
constructor(list) {
if (list === void 0 || !Array.isArray(list)) {
throw new Error('new Model Failed: list\'type error or list is undefined!')
}
this.list = list;
}
getRootNode() {
return this.list.find(item => item.id === ROOR_PID);
}
findChildren(_item) {
return this.list.filter(item => item.pid === _item.id);
}
generateTree() {
this.list.forEach(item => {
let children = this.findChildren(item);
if (children.length > 0) {
item.children = children;
}
});
let tree = this.getRootNode();
return tree;
}
}
方法二:
// 这是递归剪枝构建树的方案,时间复杂度为O(NlogN)
const ROOR_PID = null;
export default class Model {
constructor(list) {
if (list === void 0 || !Array.isArray(list)) {
throw new Error('new Model Failed: list\'type error or list is undefined!')
}
this.list = list;
}
pruneHasParant() {
let index = this.list.findIndex(item => item.hasParent);
if (index !== -1) this.list.splice(index, 1);
}
deepFindChildren(_item) {
this.pruneHasParant();
let children = this.list.filter(item => item.pid === _item.id);
if (children.length > 0) {
rpc.children = children;
children.forEach(child => {
child.hasParent = true;
this.deepFindChildren(child);
});
}
}
generateTree() {
let rootNode = this.getRootNode();
this.deepFindChildren(rootNode);
return rootNode;
}
}
采用了Class的方式,这样比较好维护内部的数据,用的时候new Model(list).generateTree()就可以了,当然根据实际数据的格式需要进行一些判断条件或逻辑的小修改,总体而言是很好用的。