Java实现多层级目录树
实现思路
1.将节点数据集合按父id分组,分组结果用Map存储
2.遍历集合,用id匹配Map的key值。若查到数据则说明Map的Value值是当前节点数据的子集合
实现代码
1. 使用Node模拟实际数据
其中id为自身id,pId为父id,children为Node子集合
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data
@NoArgsConstructor
public class Node {
private Integer id;
private Integer pId;
private List<Node> children = new ArrayList<>();
public Node(Integer id, Integer pId) {
this.id = id;
this.pId = pId;
}
}
```java
2. 实现方法
List<Node> getTrees(List<Node> nodes) {
// 根据pid分组
Map<Integer, List<Node>> nodeMap = new HashMap<>();
for (Node node : nodes) {
Integer pId = node.getPId();
if (pId != null) {
List<Node> nodeList = nodeMap.get(pId);
if (nodeList == null) {
List<Node> newNodes = new ArrayList<>();
newNodes.add(node);
nodeMap.put(pId, newNodes);
} else {
nodeList.add(node);
}
}
}
for (Node node : nodes) {
List<Node> childList = nodeMap.get(node.getId());
if (childList != null) {
node.getChildren().addAll(childList);
}
}
return nodes;
}
3.方法测试
public static void main(String[] args) {
List<Node> nodes = getNodes();
System.out.println(nodes);
List<Node> trees = getTrees(nodes);
System.out.println("---------------------------------------");
System.err.println(trees);
}
static List<Node> getNodes() {
List<Node> nodeList = new ArrayList<>();
Node node1 = new Node(1, null);
Node node2 = new Node(2, 1);
Node node3 = new Node(3, 2);
Node node4 = new Node(4, 2);
Node node5 = new Node(5, 3);
Node node6 = new Node(6, 5);
Node node7 = new Node(7, 4);
Node node8 = new Node(8, 5);
nodeList.add(node1);
nodeList.add(node2);
nodeList.add(node3);
nodeList.add(node4);
nodeList.add(node5);
nodeList.add(node6);
nodeList.add(node7);
nodeList.add(node8);
return nodeList;
}
测试结果
白色部分为原始数据,红色为N级树数据
代码优化
将分组过程用stream流实现
List<Node> getTrees(List<Node> nodes) {
Map<Integer, List<Node>> nodeMap = nodes.stream().filter(node -> node.getPId() != null).collect(Collectors.groupingBy(Node::getPId, Collectors.toList()));
for (Node node : nodes) {
List<Node> childList = nodeMap.get(node.getId());
if (CollectionUtils.isNotEmpty(childList)) {
node.getChildren().addAll(childList);
}
}
return nodes;
}
泛型化
将参数用泛型代替适用于多元化场景
package utils;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 树形化数据
*/
public class TreeListUtil {
/**
*
* @param nodes 要树形化的数据
* @param getId 获取节点id的方法
* @param getPid 获取节点父id的方法
* @param getChildren 获取子集合的方法
* @param <Node> 节点数据
* @param <Id> id的数据类型
* @param <Pid> Pid的数据类型
* @return 树形化后的数据
*/
public static <Node, Id, Pid> List<Node> getTreeList(List<Node> nodes, Function<Node, Id> getId, Function<Node, Pid> getPid, Function<Node, List<Node>> getChildren) {
Map<Pid, List<Node>> nodeMap = nodes.stream().filter(node -> getPid.apply(node) != null).collect(Collectors.groupingBy(getPid, Collectors.toList()));
for (Node node : nodes) {
List<Node> nodeList = nodeMap.get(getId.apply(node));
if (nodeList != null) {
getChildren.apply(node).addAll(nodeList);
}
}
return nodes;
}
}
泛型方法测试
public static void main(String[] args) {
List<Node> nodes = getNodes();
System.out.println(nodes);
System.out.println("---------------------------------------");
// 泛型方法调用
List<Node> treeList = TreeListUtil.getTreeList(nodes, Node::getId, Node::getPId, Node::getChildren);
System.err.println(treeList);
}
static List<Node> getNodes() {
List<Node> nodeList = new ArrayList<>();
Node node1 = new Node(1, null);
Node node2 = new Node(2, 1);
Node node3 = new Node(3, 2);
Node node4 = new Node(4, 2);
Node node5 = new Node(5, 3);
Node node6 = new Node(6, 5);
Node node7 = new Node(7, 4);
Node node8 = new Node(8, 5);
nodeList.add(node1);
nodeList.add(node2);
nodeList.add(node3);
nodeList.add(node4);
nodeList.add(node5);
nodeList.add(node6);
nodeList.add(node7);
nodeList.add(node8);
return nodeList;
}