mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add TreeBuilder
This commit is contained in:
parent
86d711cc03
commit
d05fd5af8d
@ -9,6 +9,7 @@
|
|||||||
* 【core 】 增加UserPassAuthenticator
|
* 【core 】 增加UserPassAuthenticator
|
||||||
* 【db 】 获取分组数据源时,移除公共属性项
|
* 【db 】 获取分组数据源时,移除公共属性项
|
||||||
* 【core 】 增加StrJoiner
|
* 【core 】 增加StrJoiner
|
||||||
|
* 【core 】 增加TreeBuilder
|
||||||
|
|
||||||
### 🐞Bug修复
|
### 🐞Bug修复
|
||||||
* 【db 】 修复Oracle下别名错误造成的SQL语法啊错误(issue#I3VTQW@Gitee)
|
* 【db 】 修复Oracle下别名错误造成的SQL语法啊错误(issue#I3VTQW@Gitee)
|
||||||
|
@ -563,6 +563,21 @@ public class IterUtil {
|
|||||||
return getFirst(iterable.iterator());
|
return getFirst(iterable.iterator());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取集合的第一个非空元素
|
||||||
|
*
|
||||||
|
* @param <T> 集合元素类型
|
||||||
|
* @param iterable {@link Iterable}
|
||||||
|
* @return 第一个元素
|
||||||
|
* @since 5.7.2
|
||||||
|
*/
|
||||||
|
public static <T> T getFirstNoneNull(Iterable<T> iterable) {
|
||||||
|
if (null == iterable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getFirstNoneNull(iterable.iterator());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取集合的第一个元素
|
* 获取集合的第一个元素
|
||||||
*
|
*
|
||||||
@ -577,6 +592,26 @@ public class IterUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取集合的第一个非空元素
|
||||||
|
*
|
||||||
|
* @param <T> 集合元素类型
|
||||||
|
* @param iterator {@link Iterator}
|
||||||
|
* @return 第一个非空元素,null表示未找到
|
||||||
|
* @since 5.7.2
|
||||||
|
*/
|
||||||
|
public static <T> T getFirstNoneNull(Iterator<T> iterator) {
|
||||||
|
if (null != iterator) {
|
||||||
|
while(iterator.hasNext()){
|
||||||
|
final T next = iterator.next();
|
||||||
|
if(null != next){
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得{@link Iterable}对象的元素类型(通过第一个非空元素判断)<br>
|
* 获得{@link Iterable}对象的元素类型(通过第一个非空元素判断)<br>
|
||||||
* 注意,此方法至少会调用多次next方法
|
* 注意,此方法至少会调用多次next方法
|
||||||
|
@ -0,0 +1,149 @@
|
|||||||
|
package cn.hutool.core.lang.tree;
|
||||||
|
|
||||||
|
import cn.hutool.core.builder.Builder;
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.lang.tree.parser.NodeParser;
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 树构建器
|
||||||
|
*
|
||||||
|
* @param <E> ID类型
|
||||||
|
*/
|
||||||
|
public class TreeBuilder<E> implements Builder<Tree<E>> {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final Tree<E> root;
|
||||||
|
private final Map<E, Tree<E>> idTreeMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建Tree构建器
|
||||||
|
*
|
||||||
|
* @param rootId 根节点ID
|
||||||
|
* @param <T> ID类型
|
||||||
|
* @return {@link TreeBuilder}
|
||||||
|
*/
|
||||||
|
public static <T> TreeBuilder<T> of(T rootId) {
|
||||||
|
return of(rootId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建Tree构建器
|
||||||
|
*
|
||||||
|
* @param rootId 根节点ID
|
||||||
|
* @param config 配置
|
||||||
|
* @param <T> ID类型
|
||||||
|
* @return {@link TreeBuilder}
|
||||||
|
*/
|
||||||
|
public static <T> TreeBuilder<T> of(T rootId, TreeNodeConfig config) {
|
||||||
|
return new TreeBuilder<>(rootId, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param rootId 根节点ID
|
||||||
|
* @param config 配置
|
||||||
|
*/
|
||||||
|
public TreeBuilder(E rootId, TreeNodeConfig config) {
|
||||||
|
root = new Tree<>(config);
|
||||||
|
root.setId(rootId);
|
||||||
|
this.idTreeMap = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加节点列表,增加的节点是不带子节点的
|
||||||
|
*
|
||||||
|
* @param map 节点列表
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public TreeBuilder<E> append(Map<E, Tree<E>> map) {
|
||||||
|
this.idTreeMap.putAll(map);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加节点列表,增加的节点是不带子节点的
|
||||||
|
*
|
||||||
|
* @param trees 节点列表
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public TreeBuilder<E> append(Iterable<Tree<E>> trees) {
|
||||||
|
for (Tree<E> tree : trees) {
|
||||||
|
this.idTreeMap.put(tree.getId(), tree);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加节点列表,增加的节点是不带子节点的
|
||||||
|
*
|
||||||
|
* @param list Bean列表
|
||||||
|
* @param <T> Bean类型
|
||||||
|
* @param nodeParser 节点转换器,用于定义一个Bean如何转换为Tree节点
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public <T> TreeBuilder<E> append(List<T> list, NodeParser<T, E> nodeParser) {
|
||||||
|
final TreeNodeConfig config = this.root.getConfig();
|
||||||
|
final Map<E, Tree<E>> map = new LinkedHashMap<>(list.size(), 1);
|
||||||
|
Tree<E> node;
|
||||||
|
for (T t : list) {
|
||||||
|
node = new Tree<>(config);
|
||||||
|
nodeParser.parse(t, node);
|
||||||
|
map.put(node.getId(), node);
|
||||||
|
}
|
||||||
|
return append(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Tree<E> build() {
|
||||||
|
buildFromMap();
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建树列表,例如:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* -用户管理
|
||||||
|
* --用户添加
|
||||||
|
* --用户管理
|
||||||
|
* - 部门管理
|
||||||
|
* --部门添加
|
||||||
|
* --部门管理
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @return 树列表
|
||||||
|
*/
|
||||||
|
public List<Tree<E>> buildList() {
|
||||||
|
return this.root.getChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始构建
|
||||||
|
*/
|
||||||
|
private void buildFromMap() {
|
||||||
|
final Map<E, Tree<E>> eTreeMap = MapUtil.sortByValue(this.idTreeMap, false);
|
||||||
|
List<Tree<E>> rootTreeList = CollUtil.newArrayList();
|
||||||
|
E parentId;
|
||||||
|
for (Tree<E> node : eTreeMap.values()) {
|
||||||
|
parentId = node.getParentId();
|
||||||
|
if (ObjectUtil.equals(this.root.getId(), parentId)) {
|
||||||
|
this.root.addChildren(node);
|
||||||
|
rootTreeList.add(node);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Tree<E> parentNode = eTreeMap.get(parentId);
|
||||||
|
if (null != parentNode) {
|
||||||
|
parentNode.addChildren(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,11 @@
|
|||||||
package cn.hutool.core.lang.tree;
|
package cn.hutool.core.lang.tree;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.IterUtil;
|
||||||
import cn.hutool.core.lang.tree.parser.DefaultNodeParser;
|
import cn.hutool.core.lang.tree.parser.DefaultNodeParser;
|
||||||
import cn.hutool.core.lang.tree.parser.NodeParser;
|
import cn.hutool.core.lang.tree.parser.NodeParser;
|
||||||
import cn.hutool.core.map.MapUtil;
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -18,6 +16,17 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class TreeUtil {
|
public class TreeUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建单root节点树
|
||||||
|
*
|
||||||
|
* @param list 源数据集合
|
||||||
|
* @return List
|
||||||
|
* @since 5.7.2
|
||||||
|
*/
|
||||||
|
public static Tree<Integer> buildSingle(List<TreeNode<Integer>> list) {
|
||||||
|
return buildSingle(list, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 树构建
|
* 树构建
|
||||||
*
|
*
|
||||||
@ -28,6 +37,19 @@ public class TreeUtil {
|
|||||||
return build(list, 0);
|
return build(list, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建单root节点树
|
||||||
|
*
|
||||||
|
* @param <E> ID类型
|
||||||
|
* @param list 源数据集合
|
||||||
|
* @param parentId 最顶层父id值 一般为 0 之类
|
||||||
|
* @return List
|
||||||
|
* @since 5.7.2
|
||||||
|
*/
|
||||||
|
public static <E> Tree<E> buildSingle(List<TreeNode<E>> list, E parentId) {
|
||||||
|
return buildSingle(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, new DefaultNodeParser<>());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 树构建
|
* 树构建
|
||||||
*
|
*
|
||||||
@ -40,6 +62,21 @@ public class TreeUtil {
|
|||||||
return build(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, new DefaultNodeParser<>());
|
return build(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, new DefaultNodeParser<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建单root节点树
|
||||||
|
*
|
||||||
|
* @param <T> 转换的实体 为数据源里的对象类型
|
||||||
|
* @param <E> ID类型
|
||||||
|
* @param list 源数据集合
|
||||||
|
* @param parentId 最顶层父id值 一般为 0 之类
|
||||||
|
* @param nodeParser 转换器
|
||||||
|
* @return List
|
||||||
|
* @since 5.7.2
|
||||||
|
*/
|
||||||
|
public static <T, E> Tree<E> buildSingle(List<T> list, E parentId, NodeParser<T, E> nodeParser) {
|
||||||
|
return buildSingle(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, nodeParser);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 树构建
|
* 树构建
|
||||||
*
|
*
|
||||||
@ -66,37 +103,24 @@ public class TreeUtil {
|
|||||||
* @return List
|
* @return List
|
||||||
*/
|
*/
|
||||||
public static <T, E> List<Tree<E>> build(List<T> list, E rootId, TreeNodeConfig treeNodeConfig, NodeParser<T, E> nodeParser) {
|
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);
|
return buildSingle(list, rootId, treeNodeConfig, nodeParser).getChildren();
|
||||||
Tree<E> node;
|
|
||||||
for (T t : list) {
|
|
||||||
node = new Tree<>(treeNodeConfig);
|
|
||||||
nodeParser.parse(t, node);
|
|
||||||
map.put(node.getId(), node);
|
|
||||||
}
|
|
||||||
|
|
||||||
return build(map, rootId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单点树构建,按照权重排序
|
* 构建单root节点树
|
||||||
*
|
*
|
||||||
* @param <E> ID类型
|
* @param <T> 转换的实体 为数据源里的对象类型
|
||||||
* @param map 源数据Map
|
* @param <E> ID类型
|
||||||
* @param rootId 根节点id值 一般为 0 之类
|
* @param list 源数据集合
|
||||||
* @return {@link Tree}
|
* @param rootId 最顶层父id值 一般为 0 之类
|
||||||
|
* @param treeNodeConfig 配置
|
||||||
|
* @param nodeParser 转换器
|
||||||
|
* @return List
|
||||||
* @since 5.7.2
|
* @since 5.7.2
|
||||||
*/
|
*/
|
||||||
public static <E> Tree<E> buildSingle(Map<E, Tree<E>> map, E rootId) {
|
public static <T, E> Tree<E> buildSingle(List<T> list, E rootId, TreeNodeConfig treeNodeConfig, NodeParser<T, E> nodeParser) {
|
||||||
final List<Tree<E>> list = build(map, rootId);
|
return TreeBuilder.of(rootId, treeNodeConfig)
|
||||||
if (CollUtil.isNotEmpty(list)) {
|
.append(list, nodeParser).build();
|
||||||
final TreeNodeConfig config = list.get(0).getConfig();
|
|
||||||
final Tree<E> root = new Tree<>(config);
|
|
||||||
root.setId(rootId);
|
|
||||||
root.setChildren(list);
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Tree<E>(null).setId(rootId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,22 +133,28 @@ public class TreeUtil {
|
|||||||
* @since 5.6.7
|
* @since 5.6.7
|
||||||
*/
|
*/
|
||||||
public static <E> List<Tree<E>> build(Map<E, Tree<E>> map, E rootId) {
|
public static <E> List<Tree<E>> build(Map<E, Tree<E>> map, E rootId) {
|
||||||
final Map<E, Tree<E>> eTreeMap = MapUtil.sortByValue(map, false);
|
return buildSingle(map, rootId).getChildren();
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Tree<E> parentNode = map.get(parentId);
|
/**
|
||||||
if (null != parentNode) {
|
* 单点树构建,按照权重排序
|
||||||
parentNode.addChildren(node);
|
*
|
||||||
}
|
* @param <E> ID类型
|
||||||
|
* @param map 源数据Map
|
||||||
|
* @param rootId 根节点id值 一般为 0 之类
|
||||||
|
* @return {@link Tree}
|
||||||
|
* @since 5.7.2
|
||||||
|
*/
|
||||||
|
public static <E> Tree<E> buildSingle(Map<E, Tree<E>> map, E rootId) {
|
||||||
|
final Tree<E> tree = IterUtil.getFirstNoneNull(map.values());
|
||||||
|
if (null != tree) {
|
||||||
|
final TreeNodeConfig config = tree.getConfig();
|
||||||
|
return TreeBuilder.of(rootId, config)
|
||||||
|
.append(map)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
return rootTreeList;
|
|
||||||
|
return createEmptyNode(rootId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -190,4 +220,16 @@ public class TreeUtil {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建空Tree的节点
|
||||||
|
*
|
||||||
|
* @param id 节点ID
|
||||||
|
* @param <E> 节点ID类型
|
||||||
|
* @return {@link Tree}
|
||||||
|
* @since 5.7.2
|
||||||
|
*/
|
||||||
|
public static <E> Tree<E> createEmptyNode(E id) {
|
||||||
|
return new Tree<E>().setId(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user