mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
enhance TreeUtil.build
This commit is contained in:
parent
4d7b4da46a
commit
e7fb9759f3
@ -9,6 +9,7 @@
|
||||
* 【core 】 CharSequenceUtil增加join重载(issue#I3TFJ5@Gitee)
|
||||
* 【http 】 HttpRequest增加form方法重载(pr#337@Gitee)
|
||||
* 【http 】 ImgUtil增加getMainColor方法(pr#338@Gitee)
|
||||
* 【core 】 改进TreeUtil.buid算法性能(pr#1594@Github)
|
||||
|
||||
### 🐞Bug修复
|
||||
* 【core 】 修复FileUtil.normalize去掉末尾空格问题(issue#1603@Github)
|
||||
|
@ -1,8 +1,15 @@
|
||||
package cn.hutool.core.lang.tree;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
@ -152,8 +159,32 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
|
||||
return (List<Tree<T>>) this.get(treeNodeConfig.getChildrenKey());
|
||||
}
|
||||
|
||||
public void setChildren(List<Tree<T>> children) {
|
||||
public Tree<T> setChildren(List<Tree<T>> children) {
|
||||
this.put(treeNodeConfig.getChildrenKey(), children);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加子节点,同时关联子节点的父节点为当前节点
|
||||
*
|
||||
* @param children 子节点列表
|
||||
* @return this
|
||||
* @since 5.6.7
|
||||
*/
|
||||
@SafeVarargs
|
||||
public final Tree<T> addChildren(Tree<T>... children){
|
||||
if(ArrayUtil.isNotEmpty(children)){
|
||||
List<Tree<T>> childrenList = this.getChildren();
|
||||
if(null == childrenList){
|
||||
childrenList = new ArrayList<>();
|
||||
setChildren(childrenList);
|
||||
}
|
||||
for (Tree<T> child : children) {
|
||||
child.setParent(this);
|
||||
childrenList.add(child);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -166,4 +197,29 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
|
||||
Assert.notEmpty(key, "Key must be not empty !");
|
||||
this.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringWriter stringWriter = new StringWriter();
|
||||
printTree(this, new PrintWriter(stringWriter), 0);
|
||||
return stringWriter.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印
|
||||
* @param tree 树
|
||||
* @param writer Writer
|
||||
* @param intent 缩进量
|
||||
*/
|
||||
private static void printTree(Tree<?> tree, PrintWriter writer, int intent){
|
||||
writer.println(StrUtil.format("{}{}[{}]", StrUtil.repeat(CharUtil.SPACE, intent), tree.getName(), tree.getId()));
|
||||
writer.flush();
|
||||
|
||||
final List<? extends Tree<?>> children = tree.getChildren();
|
||||
if(CollUtil.isNotEmpty(children)){
|
||||
for (Tree<?> child : children) {
|
||||
printTree(child, writer, intent + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,13 @@ package cn.hutool.core.lang.tree;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.tree.parser.DefaultNodeParser;
|
||||
import cn.hutool.core.lang.tree.parser.NodeParser;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 树工具类
|
||||
@ -58,65 +60,49 @@ public class TreeUtil {
|
||||
* @param <T> 转换的实体 为数据源里的对象类型
|
||||
* @param <E> ID类型
|
||||
* @param list 源数据集合
|
||||
* @param parentId 最顶层父id值 一般为 0 之类
|
||||
* @param rootId 最顶层父id值 一般为 0 之类
|
||||
* @param treeNodeConfig 配置
|
||||
* @param nodeParser 转换器
|
||||
* @return List
|
||||
*/
|
||||
public static <T, E> List<Tree<E>> build(List<T> list, E parentId, TreeNodeConfig treeNodeConfig, NodeParser<T, E> nodeParser) {
|
||||
final List<Tree<E>> treeList = CollUtil.newArrayList();
|
||||
Tree<E> tree;
|
||||
for (T obj : list) {
|
||||
tree = new Tree<>(treeNodeConfig);
|
||||
nodeParser.parse(obj, tree);
|
||||
treeList.add(tree);
|
||||
public static <T, E> List<Tree<E>> build(List<T> list, E rootId, TreeNodeConfig treeNodeConfig, NodeParser<T, E> nodeParser) {
|
||||
final Map<E, Tree<E>> map = new LinkedHashMap<>(list.size(), 1);
|
||||
Tree<E> node;
|
||||
for (T t : list) {
|
||||
node = new Tree<>(treeNodeConfig);
|
||||
nodeParser.parse(t, node);
|
||||
map.put(node.getId(), node);
|
||||
}
|
||||
|
||||
List<Tree<E>> finalTreeList = CollUtil.newArrayList();
|
||||
for (Tree<E> node : treeList) {
|
||||
if (ObjectUtil.equals(parentId,node.getParentId())) {
|
||||
finalTreeList.add(node);
|
||||
innerBuild(treeList, node, 0, treeNodeConfig.getDeep());
|
||||
}
|
||||
}
|
||||
// 内存每层已经排过了 这是最外层排序
|
||||
finalTreeList = finalTreeList.stream().sorted().collect(Collectors.toList());
|
||||
return finalTreeList;
|
||||
return build(map, rootId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归处理
|
||||
* 树构建,按照权重排序
|
||||
*
|
||||
* @param treeNodes 数据集合
|
||||
* @param parentNode 当前节点
|
||||
* @param deep 已递归深度
|
||||
* @param maxDeep 最大递归深度 可能为null即不限制
|
||||
* @param <E> ID类型
|
||||
* @param map 源数据Map
|
||||
* @param rootId 最顶层父id值 一般为 0 之类
|
||||
* @return List
|
||||
* @since 5.6.7
|
||||
*/
|
||||
private static <T> void innerBuild(List<Tree<T>> treeNodes, Tree<T> parentNode, int deep, Integer maxDeep) {
|
||||
public static <E> List<Tree<E>> build(Map<E, Tree<E>> map, E rootId) {
|
||||
final Map<E, Tree<E>> eTreeMap = MapUtil.sortByValue(map, false);
|
||||
List<Tree<E>> rootTreeList = CollUtil.newArrayList();
|
||||
E parentId;
|
||||
for (Tree<E> node : eTreeMap.values()) {
|
||||
parentId = node.getParentId();
|
||||
if(ObjectUtil.equals(rootId, parentId)){
|
||||
rootTreeList.add(node);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CollUtil.isEmpty(treeNodes)) {
|
||||
return;
|
||||
}
|
||||
//maxDeep 可能为空
|
||||
if (maxDeep != null && deep >= maxDeep) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 每层排序 TreeNodeMap 实现了Comparable接口
|
||||
treeNodes = treeNodes.stream().sorted().collect(Collectors.toList());
|
||||
for (Tree<T> childNode : treeNodes) {
|
||||
if (parentNode.getId().equals(childNode.getParentId())) {
|
||||
List<Tree<T>> children = parentNode.getChildren();
|
||||
if (children == null) {
|
||||
children = CollUtil.newArrayList();
|
||||
parentNode.setChildren(children);
|
||||
}
|
||||
children.add(childNode);
|
||||
// childNode.setParentId(parentNode.getId());
|
||||
childNode.setParent(parentNode);
|
||||
innerBuild(treeNodes, childNode, deep + 1, maxDeep);
|
||||
final Tree<E> parentNode = map.get(parentId);
|
||||
if(null != parentNode){
|
||||
parentNode.addChildren(node);
|
||||
}
|
||||
}
|
||||
return rootTreeList;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,7 +124,7 @@ public class TreeUtil {
|
||||
if(null == children) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// 查找子节点
|
||||
Tree<T> childNode;
|
||||
for (Tree<T> child : children) {
|
||||
@ -182,5 +168,4 @@ public class TreeUtil {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ public class TreeTest {
|
||||
static {
|
||||
// 模拟数据
|
||||
nodeList.add(new TreeNode<>("1", "0", "系统管理", 5));
|
||||
nodeList.add(new TreeNode<>("11", "1", "用户管理", 222222));
|
||||
nodeList.add(new TreeNode<>("111", "11", "用户添加", 0));
|
||||
nodeList.add(new TreeNode<>("11", "1", "用户管理", 222222));
|
||||
|
||||
nodeList.add(new TreeNode<>("2", "0", "店铺管理", 1));
|
||||
nodeList.add(new TreeNode<>("21", "2", "商品管理", 44));
|
||||
@ -33,6 +33,7 @@ public class TreeTest {
|
||||
for (Tree<String> tree : treeList) {
|
||||
Assert.assertNotNull(tree);
|
||||
Assert.assertEquals("0", tree.getParentId());
|
||||
// Console.log(tree);
|
||||
}
|
||||
|
||||
// 测试通过子节点查找父节点
|
||||
|
Loading…
x
Reference in New Issue
Block a user