开发过程中经常遇到tree结构的数据,如果是继承,那么就耦合了, 有了这个工具类,几行代码搞定常见tree查找操作
下面代码实现了任意对象的tree结构化封装,也可以是多组tree,与原对象解耦,未使用递推算法,包含了常见的对象级别,对象父节点,子节点遍历,查找方法,向上查找和向下查找,应有尽有,开箱即用.方法可能写的比较冗余,请自行精炼优化,轻喷.
性能和存储如有问题,欢迎下方给我留言.hashMap 初始化大小/0.75 = 设置大小
代码如下:
首先创建一个Node节点对象
package com.wzy.demo.node;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.commons.collections.CollectionUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* @Description:
* @Date: 2020/7/30 17:52
* @Author:wzy
* @Modified:
**/
@Setter
@Getter
@NoArgsConstructor
public class Node<T> implements Serializable {
private static final long serialVersionUID = 1L;
private String id;//id
private String pId;//父id
private String rootId;
private T value;
private List<Node<T>> childs = new ArrayList<>();
/**id**/
private List<String> parents = new ArrayList<>();
private Integer level;
public Node(String id, String pId) {
this.id = id;
this.pId = pId;
}
public Node(String id, String pId, T value) {
this.id = id;
this.pId = pId;
this.value = value;
}
public boolean haveChilds(){
return CollectionUtils.isNotEmpty(childs);
}
}
对象工具类
package com.wzy.demo.node;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Description:
* @Date: 2020/7/30 17:52
* @Author:wzy
* @Modified:
**/
@Slf4j
public class NodeUtil<T> {
private final Map<String, Node<T>> mapNode = new HashMap<>();
private List<Node<T>> allNodes = new ArrayList<>();
private Node<T> nodeTree;
private boolean isAreadyUnboxing;
private NodeUtil() {
}
/**
* 已初始化
*
* @param allNodes
*/
public NodeUtil(List<Node<T>> allNodes) {
this.allNodes = allNodes;
for (Node<T> node : allNodes) {
mapNode.put(node.getId(), node);
}
nodeTree = this.getTree();
}
/**
* 查找集合的所有根节点,不包含子节点
*
* @param <T>
* @return
*/
public <T> List<Node<T>> findRoots() {
List<Node<T>> results = new ArrayList();
for (Node node : allNodes) {
boolean isRoot = true;
for (Node comparedOne : allNodes) {
if (StringUtils.equals(node.getPId(), comparedOne.getId())) {
isRoot = false;
break;
}
}
if (isRoot) {
//node.setLevel(0);
results.add(node);
node.setRootId(node.getId());
}
}
return results;
}
测试bean
package com.wzy.demo;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
/**
*
@Description:
@Date: 2020/10/17 22:43
@Author:wzy
@Modified:
**/
@Getter
@Setter
public class TestTreeNodeBean {
private String id;
private String pid;
private String name;
private List<TestTreeNodeBean> children;
private Integer level;
public TestTreeNodeBean(String id, String pid, String name) {
this.id = id;
this.pid = pid;
this.name = name;
}
}
测试工具类
package com.wzy.demo;
import com.alibaba.fastjson.JSON;
import com.wzy.demo.node.Node;
import com.wzy.demo.node.NodeUtil;
import lombok.extern.slf4j.Slf4j;
import net.minidev.json.JSONArray;
import org.apache.commons.collections.CollectionUtils;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Description:
* @Date: 2020/10/17 22:32
* @Author:wzy
* @Modified:
**/
@Slf4j
public class TestNode {
@Test
public void s2() {
TestTreeNodeBean beanRoot =new TestTreeNodeBean("0","-1","根目录");
TestTreeNodeBean child1 =new TestTreeNodeBean("1","0","根目录");
TestTreeNodeBean child2 =new TestTreeNodeBean("2","0","根目录");
TestTreeNodeBean child3 =new TestTreeNodeBean("3","1","根目录");
TestTreeNodeBean child4 =new TestTreeNodeBean("4","1","根目录");
TestTreeNodeBean child6 =new TestTreeNodeBean("6","1","根目录");
TestTreeNodeBean child7 =new TestTreeNodeBean("7","6","根目录");
TestTreeNodeBean child5 =new TestTreeNodeBean("5","2","根目录");
List<TestTreeNodeBean> originalDate = new ArrayList<TestTreeNodeBean>(){
{
add(beanRoot); add(child1); add(child2); add(child3); add(child4); add(child5);
add(child6);add(child7);
}
};
List<Node<TestTreeNodeBean>> allNodes;
allNodes = originalDate.stream().map(s -> new Node<>(s.getId(), s.getPid(), s)).collect(Collectors.toList());
NodeUtil<TestTreeNodeBean> tree = new NodeUtil<>(allNodes);
this.unBoxingDate(tree);
log.info("tree:[{}]", JSON.toJSONString(tree));
log.info("tree:[{}]", JSON.toJSONString(tree.getAllParentNode(tree.getMapNode().get(child7.getId()))));
log.info("end:[{}]", "no thing");
}
@Test
private void s1() {
List<Node<String>> allNodes = new ArrayList<>();
Node<String> nodeTest = new Node<>("9", "8", "你10");
Node<String> node4 = new Node<String>("4", "1", "你5");
allNodes.add(new Node<>("-1", "9999", "你1"));
allNodes.add(new Node<>("1", "0", "你2"));
allNodes.add(new Node<>("2", "0", "你3"));
allNodes.add(new Node<>("3", "0", "你4"));
allNodes.add(node4);
allNodes.add(new Node<>("5", "1", "你6"));
allNodes.add(new Node<>("6", "2", "你7"));
allNodes.add(new Node<>("7", "2", "你8"));
allNodes.add(new Node<>("8", "4", "你9"));
allNodes.add(nodeTest);
allNodes.add(new Node<>("10", "8", "你11"));
NodeUtil<String> util = new NodeUtil<>(allNodes);
List<Node<String>> values = new ArrayList<>();
values = util.findRoots();
Node<String> nodeTree = util.getNodeTree();
for (Node<String> child : nodeTree.getChilds()) {
int levelInt = util.getNodeLevel(nodeTree, nodeTest);
log.info("node level:[{}][{}]", child.getValue(), levelInt);
}
List<Node<String>> parentNodes = util.getAllParentNode(nodeTest);
StringBuffer sb = new StringBuffer();
parentNodes.forEach(s -> {
sb.append(s.getValue()).append("/");
});
//sb =你2/你5/你9/ 这里拿到了所有的父节点
List<Node<String>> childNodes = util.getAllChildNode(util.getMapNode().get(node4.getId()));
log.info("childNodes:[{}]", JSONArray.toJSONString(childNodes));
}
/**
* 如果是对象,例如有id,pid, List<T> children; 三个参数,
* 当创建nodeTree后,其实原始对象里这些数据还没有值,所以这里做一步赋值操作
* 其实这里应该可以用反射做,比较通用
*
* @param
*/
private void unBoxingDate(NodeUtil<TestTreeNodeBean> nodeUtil) {
if (nodeUtil.isAreadyUnboxing()) {
return;
}
nodeUtil.setAreadyUnboxing(true);
Node<TestTreeNodeBean> categoryNode = nodeUtil.getNodeTree();
List<Node<TestTreeNodeBean>> temp = new ArrayList<>();
temp.add(categoryNode);
do {
for (Node<TestTreeNodeBean> tree : temp) {
if (tree.getValue() == null) {
//tree.setValue(new CategoryBean());
continue;
}
if (tree.getValue().getChildren() == null) {
tree.getValue().setChildren(new ArrayList<>());
}
if (CollectionUtils.isEmpty(tree.getChilds())) {
return;
}
for (Node<TestTreeNodeBean> child : tree.getChilds()) {
if (tree.getValue().getLevel() == null) {
tree.getValue().setLevel(tree.getLevel());
}
child.getValue().setLevel(child.getLevel());
tree.getValue().getChildren().add(child.getValue());
}
}
temp = temp.stream().flatMap(s -> s.getChilds().stream()).collect(Collectors.toList());
} while (org.apache.commons.collections.CollectionUtils.isNotEmpty(temp));
}
}