java 处理树形结构 树形转为list list转为树形
- 🍇树形转为list
- 🍇每个节点对祖级列表的编号List赋值
- 🍇list转为树形
- 方式1
- 方式2(使用stream,如果id是唯一的话,比递归效率快)
- 方式3(使用插件)
- 从数据查询树
- 1.添加数据的时候加入祖父列表字段,方便匹配(推荐)
- 2.Mysql进行树形查询
实体类结构:
@Data
@NoArgsConstructor
@AllArgsConstructor
class Node {
// id
private Integer id;
// 父id
private Integer pId;
// 名称
private String name;
// 祖级id列表
private List<Integer> ancestors;
// 子节点
private List<Node> children;
public Node(int id, int pId, String name) {
this.id = id;
this.pId = pId;
this.name = name;
}
@Override
public String toString() {
return "Node{" +
"id=" + id +
", pId=" + pId +
", name='" + name + '\'' +
", ancestors=" + ancestors +
", children=" + children +
'}';
}
}
🍇树形转为list
@Test
public void test01() {
// 填充数据
Node level4 = new Node(4, 3, "level4-01");
Node level3 = new Node(3, 2, "level3-01");
Node level2 = new Node(2, 1, "level2-01");
Node level22 = new Node(22, 1, "level2-02");
Node level1 = new Node(1, 0, "level1-01");
List<Node> level3children = new ArrayList<>();
level3children.add(level4);
level3.setChildren(level3children);
List<Node> level2children = new ArrayList<>();
level2children.add(level3);
level2.setChildren(level2children);
List<Node> children = new ArrayList<>();
children.add(level2);
children.add(level22);
level1.setChildren(children);
System.out.println(level1.toString());
System.out.println("===============before===============");
// 树形转为list
List<Node> result = new ArrayList<>();
this.recursionTreeToList(result, level1, null);
for (Node node : result) {
node.setChildren(null);
System.out.println(node.toString());
}
System.out.println("===============after===============");
}
/**
* 递归把传过来的tree转为list
*
* @param result 结果集
* @param root 当前对象
* @param parentNode 没有传Null
*/
public void recursionTreeToList(List<Node> result, Node root, Node parentNode) {
// 如果没有pid那么就赋值
/* if (parentNode != null) {
root.setPid(parentNode.getEid());
}*/
result.add(root);
if (CollectionUtils.isEmpty(root.getChildren())) {
return;
}
for (Node child : root.getChildren()) {
this.recursionTreeToList(result, child, root);
}
}
结果如下:
🍇每个节点对祖级列表的编号List赋值
@Test
public void test01() {
// 填充数据
Node level4 = new Node(4, 3, "level4-01");
Node level3 = new Node(3, 2, "level3-01");
Node level2 = new Node(2, 1, "level2-01");
Node level22 = new Node(22, 1, "level2-02");
Node level1 = new Node(1, 0, "level1-01");
List<Node> level3children = new ArrayList<>();
level3children.add(level4);
level3.setChildren(level3children);
List<Node> level2children = new ArrayList<>();
level2children.add(level3);
level2.setChildren(level2children);
List<Node> children = new ArrayList<>();
children.add(level2);
children.add(level22);
level1.setChildren(children);
System.out.println(level1.toString());
System.out.println("===============before===============");
// 树形转为list
List<Node> result = new ArrayList<>();
this.recursionTreeToList(result, level1, null);
for (Node node : result) {
node.setChildren(null);
System.out.println(node.toString());
}
System.out.println("===============after===============");
// 处理祖父列表
this.handleAncestors(result);
for (Node node : result) {
System.out.println(node.toString());
}
System.out.println("===============handle ancestors after===============");
}
/**
* 递归把传过来的tree转为list
*
* @param result 结果集
* @param root 当前对象
* @param parentNode 没有传Null
*/
public void recursionTreeToList(List<Node> result, Node root, Node parentNode) {
// 如果没有pid那么就赋值
/* if (parentNode != null) {
root.setPid(parentNode.getEid());
}*/
result.add(root);
if (CollectionUtils.isEmpty(root.getChildren())) {
return;
}
for (Node child : root.getChildren()) {
this.recursionTreeToList(result, child, root);
}
}
List<Integer> ancestors = new ArrayList<>();
/**
* 给list赋值祖父节点
* @param list
*/
public void handleAncestors(List<Node> list) {
for (Node node : list) {
ancestors = new ArrayList<>();
List<Integer> ancestorsList = this.recursionAncestors(list, node);
ancestorsList.add(node.getId());
node.setAncestors(ancestorsList);
}
}
/**
* 根据当前节点查询他的祖父列表
* @param list 数据List
* @param n 当前节点
* @return 所有父节点
*/
public List<Integer> recursionAncestors(List<Node> list, Node n) {
if (n.getId() == null) {
return ancestors;
}
for (Node node : list) {
if (n.getPId() == node.getId()) {
this.recursionAncestors(list, node);
ancestors.add(node.getId());
}
}
return ancestors;
}
结果如下:
🍇list转为树形
方式1
@Test
public void test01() {
// 填充数据
Node level4 = new Node(4, 3, "level4-01");
Node level3 = new Node(3, 2, "level3-01");
Node level2 = new Node(2, 1, "level2-01");
Node level22 = new Node(22, 1, "level2-02");
Node level1 = new Node(1, 0, "level1-01");
List<Node> level3children = new ArrayList<>();
level3children.add(level4);
level3.setChildren(level3children);
List<Node> level2children = new ArrayList<>();
level2children.add(level3);
level2.setChildren(level2children);
List<Node> children = new ArrayList<>();
children.add(level2);
children.add(level22);
level1.setChildren(children);
System.out.println(level1.toString());
System.out.println("=============== before Tree To List ===============");
List<Node> result = new ArrayList<>();
// 树形转为list
this.recursionTreeToList(result, level1, null);
for (Node node : result) {
node.setChildren(null);
System.out.println(node.toString());
}
System.out.println("=============== after Tree To List ===============");
// 处理祖父列表
this.handleAncestors(result);
for (Node node : result) {
System.out.println(node.toString());
}
System.out.println("===============handle ancestors after===============");
List<Node> nodes = this.recursionListToTree(result, 0);
for (Node node : nodes) {
System.out.println(node.toString());
}
System.out.println("=============== after List To Tree ===============");
}
/**
* 递归把传过来的tree转为list
*
* @param result 结果集
* @param root 当前对象
* @param parentNode 没有传Null
*/
public void recursionTreeToList(List<Node> result, Node root, Node parentNode) {
// 如果没有pid那么就赋值
/* if (parentNode != null) {
root.setPid(parentNode.getEid());
}*/
result.add(root);
if (CollectionUtils.isEmpty(root.getChildren())) {
return;
}
for (Node child : root.getChildren()) {
this.recursionTreeToList(result, child, root);
}
}
/**
* 递归方法把传过来的list转为tree
*
* @param tree 父节点对象
* @param treeList 所有的List
* @return
*/
public List<Node> recursionListToTree(List<Node> list, int pId) {
List<Node> nodes = new ArrayList<>();
for (Node node : list) {
// 找出父节点
if (pId == node.getPId()) {
// 调用递归方法填充子节点列表
nodes.add(this.findChildren(node, list));
}
}
return nodes;
}
/**
* 递归方法
*
* @param tree 父节点对象
* @param treeList 所有的List
* @return
*/
public Node findChildren(Node tree, List<Node> treeList) {
for (Node node : treeList) {
if (tree.getId().equals(node.getPId())) {
if (CollectionUtils.isEmpty(tree.getChildren())) {
tree.setChildren(new ArrayList<>());
}
// 递归 调用自身
tree.getChildren().add(this.findChildren(node, treeList));
}
}
return tree;
}
List<Integer> ancestors = new ArrayList<>();
/**
* 给list赋值祖父节点
*
* @param list
*/
public void handleAncestors(List<Node> list) {
for (Node node : list) {
ancestors = new ArrayList<>();
List<Integer> ancestorsList = this.recursionAncestors(list, node);
ancestorsList.add(node.getId());
node.setAncestors(ancestorsList);
}
}
/**
* 根据当前节点查询他的祖父列表
*
* @param list 数据List
* @param n 当前节点
* @return 所有父节点
*/
public List<Integer> recursionAncestors(List<Node> list, Node n) {
if (n.getId() == null) {
return ancestors;
}
for (Node node : list) {
if (n.getPId() == node.getId()) {
this.recursionAncestors(list, node);
ancestors.add(node.getId());
}
}
return ancestors;
}
结果如图:
方式2(使用stream,如果id是唯一的话,比递归效率快)
/**
* stream把传过来的list转为tree
*
* @param tree 父节点对象
* @param treeList 所有的List
* @return
*/
public List<Node> handleListToTree(List<Node> list, int pId) {
List<Node> nodes = new ArrayList<>();
Map<String, List<Node>> nodeMap = list.stream().collect(Collectors.groupingBy(Node::getPId));
list.forEach(n -> { n.setChildren(nodeMap.get(n.getPId())); });
nodes = list.stream().filter(n -> n.getPId().equals(pId)).collect(Collectors.toList());
return nodes;
}
方式3(使用插件)
1.导入jar包
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- -->
<!-- liu https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
</dependencies>
2.编写代码
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import lombok.*;
import org.junit.Test;
import java.util.*;
/**
* @author: doris
* @date: 2023/7/6 13:27
*/
public class TestTree {
@Data
@NoArgsConstructor
@AllArgsConstructor
class Node {
// id
private String id;
// 父id
private String pId;
// 名称
private String name;
// 祖级id列表 ,
private String ancestors;
// 子节点
private List<Node> children;
}
@Test
public void test01() {
List<Node> list = new ArrayList<>();
list.add(new Node("0", "999999", "level", "999999", null));
list.add(new Node("1", "0", "level1", "999999,0", null));
list.add(new Node("2", "1", "level2", "999999,0,1", null));
list.add(new Node("3", "2", "level3", "999999,0,1,2", null));
System.out.println("======================start======================");
Multimap<String, Node> myMultimap = ArrayListMultimap.create();
for (Node node : list) {
System.out.println(node);
myMultimap.put(node.getPId(), node);
}
Node build = list.get(0);
Node tree = createTree(build, myMultimap);
System.out.println(tree);
}
/**
* 创建树形数据
* @param build 顶点
* @param myMultimap 树
* @return
*/
public Node createTree(Node build, Multimap<String, Node> myMultimap) {
if (myMultimap.get(build.getId()) != null) {
List<Node> list = (List<Node>) myMultimap.get(build.getId());
recursionData(list, myMultimap);
build.setChildren(list);
}
return build;
}
public void recursionData(Collection<Node> list, Multimap<String, Node> myMultimap) {
for (Node node : list) {
if (myMultimap.get(node.getId()) != null) {
List<Node> t = (List<Node>) myMultimap.get(node.getId());
recursionData(t, myMultimap);
node.setChildren(t);
}
}
}
}
3.结果:
从数据查询树
1.添加数据的时候加入祖父列表字段,方便匹配(推荐)
select * from tb1 where FIND_IN_SET('id',祖父列表字段) > 0
2.Mysql进行树形查询
SELECT DISTINCT tb1.id, pid
FROM tb1, ( SELECT @pid := 'id' ) pd
WHERE
FIND_IN_SET( pid, @pid ) > 0
AND @pid := concat( @pid, ',', id )
UNION SELECT id, pid FROM tb1 WHERE id = 'id ';