cn.hutool.core.lang.tree.TreeUtil Maven / Gradle / Ivy
Show all versions of hutool-all Show documentation
package cn.hutool.core.lang.tree;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.lang.tree.parser.DefaultNodeParser;
import cn.hutool.core.lang.tree.parser.NodeParser;
import cn.hutool.core.util.ObjectUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 树工具类
*
* @author liangbaikai
*/
public class TreeUtil {
/**
* 构建单root节点树
*
* @param list 源数据集合
* @return {@link Tree}
* @since 5.7.2
*/
public static Tree buildSingle(List> list) {
return buildSingle(list, 0);
}
/**
* 树构建
*
* @param list 源数据集合
* @return List
*/
public static List> build(List> list) {
return build(list, 0);
}
/**
* 构建单root节点树
* 它会生成一个以指定ID为ID的空的节点,然后逐级增加子节点。
*
* @param ID类型
* @param list 源数据集合
* @param parentId 最顶层父id值 一般为 0 之类
* @return {@link Tree}
* @since 5.7.2
*/
public static Tree buildSingle(List> list, E parentId) {
return buildSingle(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, new DefaultNodeParser<>());
}
/**
* 树构建
*
* @param ID类型
* @param list 源数据集合
* @param parentId 最顶层父id值 一般为 0 之类
* @return List
*/
public static List> build(List> list, E parentId) {
return build(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, new DefaultNodeParser<>());
}
/**
* 构建单root节点树
* 它会生成一个以指定ID为ID的空的节点,然后逐级增加子节点。
*
* @param 转换的实体 为数据源里的对象类型
* @param ID类型
* @param list 源数据集合
* @param parentId 最顶层父id值 一般为 0 之类
* @param nodeParser 转换器
* @return {@link Tree}
* @since 5.7.2
*/
public static Tree buildSingle(List list, E parentId, NodeParser nodeParser) {
return buildSingle(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, nodeParser);
}
/**
* 树构建
*
* @param 转换的实体 为数据源里的对象类型
* @param ID类型
* @param list 源数据集合
* @param parentId 最顶层父id值 一般为 0 之类
* @param nodeParser 转换器
* @return List
*/
public static List> build(List list, E parentId, NodeParser nodeParser) {
return build(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, nodeParser);
}
/**
* 树构建
*
* @param 转换的实体 为数据源里的对象类型
* @param ID类型
* @param list 源数据集合
* @param rootId 最顶层父id值 一般为 0 之类
* @param treeNodeConfig 配置
* @param nodeParser 转换器
* @return List
*/
public static List> build(List list, E rootId, TreeNodeConfig treeNodeConfig, NodeParser nodeParser) {
return buildSingle(list, rootId, treeNodeConfig, nodeParser).getChildren();
}
/**
* 构建单root节点树
* 它会生成一个以指定ID为ID的空的节点,然后逐级增加子节点。
*
* @param 转换的实体 为数据源里的对象类型
* @param ID类型
* @param list 源数据集合
* @param rootId 最顶层父id值 一般为 0 之类
* @param treeNodeConfig 配置
* @param nodeParser 转换器
* @return {@link Tree}
* @since 5.7.2
*/
public static Tree buildSingle(List list, E rootId, TreeNodeConfig treeNodeConfig, NodeParser nodeParser) {
return TreeBuilder.of(rootId, treeNodeConfig)
.append(list, rootId, nodeParser).build();
}
/**
* 树构建,按照权重排序
*
* @param ID类型
* @param map 源数据Map
* @param rootId 最顶层父id值 一般为 0 之类
* @return List
* @since 5.6.7
*/
public static List> build(Map> map, E rootId) {
return buildSingle(map, rootId).getChildren();
}
/**
* 单点树构建,按照权重排序
* 它会生成一个以指定ID为ID的空的节点,然后逐级增加子节点。
*
* @param ID类型
* @param map 源数据Map
* @param rootId 根节点id值 一般为 0 之类
* @return {@link Tree}
* @since 5.7.2
*/
public static Tree buildSingle(Map> map, E rootId) {
final Tree tree = IterUtil.getFirstNoneNull(map.values());
if (null != tree) {
final TreeNodeConfig config = tree.getConfig();
return TreeBuilder.of(rootId, config)
.append(map)
.build();
}
return createEmptyNode(rootId);
}
/**
* 获取ID对应的节点,如果有多个ID相同的节点,只返回第一个。
* 此方法只查找此节点及子节点,采用递归深度优先遍历。
*
* @param ID类型
* @param node 节点
* @param id ID
* @return 节点
* @since 5.2.4
*/
public static Tree getNode(Tree node, T id) {
if (ObjectUtil.equal(id, node.getId())) {
return node;
}
final List> children = node.getChildren();
if (null == children) {
return null;
}
// 查找子节点
Tree childNode;
for (Tree child : children) {
childNode = child.getNode(id);
if (null != childNode) {
return childNode;
}
}
// 未找到节点
return null;
}
/**
* 获取所有父节点名称列表
*
*
* 比如有个人在研发1部,他上面有研发部,接着上面有技术中心
* 返回结果就是:[研发一部, 研发中心, 技术中心]
*
* @param 节点ID类型
* @param node 节点
* @param includeCurrentNode 是否包含当前节点的名称
* @return 所有父节点名称列表,node为null返回空List
* @since 5.2.4
*/
public static List getParentsName(Tree node, boolean includeCurrentNode) {
final List result = new ArrayList<>();
if (null == node) {
return result;
}
if (includeCurrentNode) {
result.add(node.getName());
}
Tree parent = node.getParent();
CharSequence name;
while (null != parent) {
name = parent.getName();
parent = parent.getParent();
if(null != name || null != parent){
// issue#I795IN,根节点的null不加入
result.add(name);
}
}
return result;
}
/**
* 获取所有父节点ID列表
*
*
* 比如有个人在研发1部,他上面有研发部,接着上面有技术中心
* 返回结果就是:[研发部, 技术中心]
*
* @param 节点ID类型
* @param node 节点
* @param includeCurrentNode 是否包含当前节点的名称
* @return 所有父节点ID列表,node为null返回空List
* @since 5.8.22
*/
public static List getParentsId(Tree node, boolean includeCurrentNode) {
final List result = new ArrayList<>();
if (null == node) {
return result;
}
if (includeCurrentNode) {
result.add(node.getId());
}
Tree parent = node.getParent();
T id;
while (null != parent) {
id = parent.getId();
parent = parent.getParent();
if(null != id || null != parent){
// issue#I795IN,根节点的null不加入
result.add(id);
}
}
return result;
}
/**
* 创建空Tree的节点
*
* @param id 节点ID
* @param 节点ID类型
* @return {@link Tree}
* @since 5.7.2
*/
public static Tree createEmptyNode(E id) {
return new Tree().setId(id);
}
}