问题描述

source:

/a/b/c/d/e
/a/b/e/f/g
/a/b/h
/a/i/j
/a/i/k

what I need:

a
/ \
b i
/|\ / \
c e h j k
| |
d f
| |
e g

程序源代码

JavaScript

let treeDTO = [];
let array = [
'a/b/c/d/e',
'a/b/e/f/g',
'a/b/h',
'a/i/j',
'a/i/k'
];

array.map((item) => {
let key = item; // key is the full path
let nodeArray = key.split('/'); // split the full path with '/'
// 递归
let children = treeDTO;

// 构建根节点
if (children.length == 0) {
let root = {
key: nodeArray[0]
};
if (nodeArray.length > 1) {
root.children = [];
}
children.push(root);
} else {
// 循环构建子节点
for (let i in nodeArray) {
console.log("i:" + i);
console.log("nodeArray:" + nodeArray);

let node = {
key: nodeArray[i]
};

if (i != nodeArray.length) {
node.children = [];
}

if (children.length == 0) {
children.push(node);
}

let isExist = false;

for (let j in children) {
console.log("j:" + j);

if (children[j].key == node.key) {
if (i != nodeArray.length - 1 && !children[j].children) {
children[j].children = [];
}
children = (i == nodeArray.length - 1 ? children : children[j].children);

console.log("children:" + JSON.stringify(children));

isExist = true;
break;
}
}

if (!isExist) {
children.push(node);
if (i != nodeArray.length - 1 && !children[children.length - 1].children) {
children[children.length - 1].children = [];
}
children = (i == nodeArray.length - 1 ? children : children[children.length - 1].children);
}

}
}
});

console.log(treeDTO);

/* source:
/a/b/c/d/e
/a/b/e/f/g
/a/b/h
/a/i/j
/a/i/k

what I need:

a
/ \
b i
/|\ / \
c e h j k
| |
d f
| |
e g
*/

Java

节点是通用泛型数据模型:

import com.alibaba.fastjson.JSON;

import java.util.Arrays;

/**
* @author: Jack
* 2020-01-11 00:17
*/
public class Main {
public static void main(String[] args) {
Tree<String> forest = new Tree<String>("root");
Tree<String> current = forest;

for (String tree :
Arrays.asList(
"a/b/c/d/e",
"a/b/e/f/g",
"a/b/h",
"a/i/j",
"a/i/k")) {


Tree<String> root = current;

for (String data : tree.split("/")) {
current = current.child(data);
}

current = root;

}

forest.accept(new TreeVisitor());

System.out.println(JSON.toJSONString(forest));
}
}



import java.util.LinkedHashSet;
import java.util.Set;

/**
* @author: Jack
* 2020-01-11 00:13
*/
class Tree<T> implements Visitable<T> {
// NB: LinkedHashSet preserves insertion order
private Set<Tree> children = new LinkedHashSet<Tree>();
private T data;

Tree(T data) {
this.data = data;
}

public void accept(Visitor<T> visitor) {
visitor.visitData(this, data);

for (Tree child : children) {
Visitor<T> childVisitor = visitor.visitTree(child);
child.accept(childVisitor);
}
}

Tree child(T data) {
for (Tree child : children) {
if (child.data.equals(data)) {
return child;
}
}
return child(new Tree(data));
}

Tree child(Tree<T> child) {
children.add(child);
return child;
}

public Set<Tree> getChildren() {
return children;
}

public void setChildren(Set<Tree> children) {
this.children = children;
}

public T getData() {
return data;
}

public void setData(T data) {
this.data = data;
}
}



/**
* @author: Jack
* 2020-01-11 00:13
*/
interface Visitor<T> {

Visitor<T> visitTree(Tree<T> tree);

void visitData(Tree<T> parent, T data);
}



/**
* @author: Jack
* 2020-01-11 00:13
*/
interface Visitable<T> {

void accept(Visitor<T> visitor);
}




/**
* @author: Jack
* 2020-01-11 00:15
*/
class TreeVisitor implements Visitor<String> {
TreeVisitor() {
}

public Visitor<String> visitTree(Tree<String> tree) {
return new TreeVisitor();
}

public void visitData(Tree<String> parent, String data) {
}
}

Kotlin

自定义具体化的节点模型:

import java.util.*

/**
* @author: Jack
* 2020-01-11 02:35
*/
class NavTree : NavVisitable {
var deptNo = ""
var deptName = ""
var hasPermission = false
var leaf = false
var children: MutableSet<NavTree> = LinkedHashSet()

constructor(deptNo: String, deptName: String, hasPermission: Boolean, leaf: Boolean) {
this.deptNo = deptNo
this.deptName = deptName
this.hasPermission = hasPermission
this.leaf = leaf
}


/**
* 递归遍历
*/
override fun visit(visitor: NavVisitor) {
visitor.visitTree(this)
for (child in children) {
val childVisitor = visitor.visitTree(child)
child.visit(childVisitor)
}
}


fun children(data: NavTree): NavTree {
for (child in children) {
if (child.deptNo == data.deptNo) {
return child
}
}
children.add(data)
return data
}
}


/**
* @author: Jack
* 2020-01-11 00:15
*/
class NavTreeVisitor : NavVisitor {

override fun visitTree(tree: NavTree): NavVisitor {

return NavTreeVisitor()
}

}


/**
* @author: Jack
* 2020-01-11 00:13
*/
interface NavVisitable {
fun visit(visitor: NavVisitor)
}


/**
* @author: Jack
* 2020-01-11 00:13
*/
interface NavVisitor {

fun visitTree(tree: NavTree): NavVisitor
}


/**
* 构建导航树
* source:
/a/b/c/d/e
/a/b/e/f/g
/a/b/h
/a/i/j
/a/i/k

transform to:

a
/ \
b i
/|\ / \
c e h j k
| |
d f
| |
e g
*/
private fun buildAlibrainNavTree(authorizedDepts: List<DataPermissionDeptDTO>, hasPermissionDeptMap: MutableMap<String, DataPermissionDeptDTO>, deptInfoMap: MutableMap<String, String>): NavTree {
// 顶级根节点
var rootNode = NavTree(
deptNo = "00001",
deptName = "XXX",
leaf = false,
hasPermission = false
)

var current = rootNode

authorizedDepts.map {
val root = current
val length = it.deptNoArray.size

it.deptNoArray.forEachIndexed { index, e ->
val data = NavTree(
deptNo = e,
deptName = deptInfoMap[e] ?: "",
leaf = (index == length - 1),
hasPermission = (hasPermissionDeptMap[e] != null)
)
current = current.children(data)
}

current = root
}

rootNode.visit(NavTreeVisitor())
return rootNode
}

Kotlin 开发者社区


Java 、Kotlin、JavaScript 把全路径列表转换成树状层级嵌套结构_开发者社区


国内第一Kotlin 开发者社区公众号,主要分享、交流 Kotlin 编程语言、Spring Boot、Android、React.js/Node.js、函数式编程、编程思想等相关主题。

越是喧嚣的世界,越需要宁静的思考。