公司项目有个需求,用户通过网页对目录结果进行编辑后,产生了如下的数组结构,后台需要对这个数组转换成一个森林,然后方便的进行渲染。
这个数组原型大概如下图,
|—— 根目录 level:-1
|—— 目录A level:0
|—— 目录A_1 level:1
|—— 目录A_1_1 level:2
|—— 目录A_2 level:1
|—— 目录A_2_1 level:2
|—— 目录A_2_1_1 level:3
|—— 目录A_2_1_1_1 level:4
|—— 目录A_3 level:1
|—— 目录A_3_1 level:2
|—— 目录A_3_2 level:2
|—— 目录B level:0
|—— 目录B_1 level:1
|—— 目录B_1_1 level:2
|—— 目录B_1_1_1 level:3
|—— 目录B_2 level:1
|—— 目录C level:0
..........
数组结果类似下图(上面的结构和下面的数组并不匹配,只是一个栗子)
[
{
value: '根目录',
level: -1,
childs: [],
},
{
value: '目录A',
level: 0,
childs: []
},
{
value: '目录A_1',
level: 1,
childs: []
},
{
value: '目录A_1_1',
level: 2,
childs: []
},
{
value: '目录A_2',
level: 1,
childs: []
},
{
value: '目录B',
level: 0,
childs: []
},
{
value: '目录B_1',
level: 1,
childs: []
},
{
value: '目录B_1_1',
level: 2,
childs: []
},
{
value: '目录B_1_2',
level: 2,
childs: []
},
{
value: '目录B_1_2_1',
level: 3,
childs: []
},
{
value: '目录C',
level: 0,
childs: []
},
];
从上向下遍历数组然后比较,判断父子节点的关系也可以建立这颗森林,我想的是从最深的节点开始,对树进行收敛。中心思想是:找到最深的节点,判断它上一个节点,如果是它的父,则建立父子关系,然后重新寻找最深的节点;如果是它的兄弟,则建立兄弟关系,然后兄弟抱团去找他们的父亲(他两合并变成最深的节点,继续向上找一个节点),循环如此,直到找到根节点为止。
算法使用JS实现如下,buildTree是入口方法,参数就是我们需要转换的数组结构,返回值为结果森林。
/**
* 建立树
*/
function buildTree(source) {
if (source.length == 1) {
return source;
}
var index = indexOfMaxLevel(source);
var target = source[index];
return restrainTree(source, target, index);
}
/**
* 对树本身进行收敛拼接
* index表示当前node所在的source的位置
*/
function restrainTree(source, node, index) {
var preIndex = index - 1;
if (preIndex < 0) {
console.log("这里出现应该是树错误")
return source;
}
// 从当前节点往上取一个节点进行比较
var pre = source[preIndex];
// 取出最顶上面的节点,也就是当前节点
var cur = Array.isArray(node) ? node[0] : node;
if (pre.level < cur.level) {
// 处理节点
pre.childs = node;
// 将已经处理的数据清理,防止多次处理
source = removeFromArray(source, index, node);
// 重新开始build
return buildTree(source);
} else if (pre.level == cur.level) {
var tmp = [];
tmp = tmp.concat(pre).concat(node);
// 合并节点后,继续向上
return restrainTree(source, tmp, preIndex);
} else {
console.log("应该不存在吧....")
}
}
/**
* 清理树中已经处理过的节点
*/
function removeFromArray(arr, index, node) {
var size = 1;
if (Array.isArray(node)) {
size = node.length;
}
return arr.slice(0, index).concat(arr.slice(index + size, arr.length));
}
// 获得最大层数的index
function indexOfMaxLevel(arr) {
var index = -1;
var max = -1;
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
if (item.level >= max) {
max = item.level;
index = i;
}
}
return index;
}