diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeUtil.java b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeUtil.java index 7577e496e..e44bc3c9e 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeUtil.java @@ -5,9 +5,10 @@ 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; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.stream.Collectors; /** * 树工具类 @@ -277,4 +278,52 @@ public class TreeUtil { public static Tree createEmptyNode(E id) { return new Tree().setId(id); } + + /** + * 函数式构建树状结构(无需继承Tree类) + * + * @param nodes 需要构建树集合 + * @param rootId 根节点ID + * @param idFunc 获取节点ID函数 + * @param parentIdFunc 获取节点父ID函数 + * @param setChildFunc 设置孩子集合函数 + * @param 节点ID类型 + * @param 节点类型 + * @return List + */ + public static List build(List nodes, T rootId, Function idFunc, Function parentIdFunc, BiConsumer> setChildFunc) { + List rootList = nodes.stream().filter(tree -> parentIdFunc.apply(tree).equals(rootId)).collect(Collectors.toList()); + Map filterOperated = new HashMap<>(rootList.size() + nodes.size()); + //对每个根节点都封装它的孩子节点 + rootList.forEach(root -> setChildren(root, nodes, filterOperated, idFunc, parentIdFunc, setChildFunc)); + return rootList; + } + + /** + * 封装孩子节点 + * + * @param root 根节点 + * @param nodes 节点集合 + * @param filterOperated 过滤操作Map + * @param idFunc 获取节点ID函数 + * @param parentIdFunc 获取节点父ID函数 + * @param setChildFunc 设置孩子集合函数 + * @param 节点ID类型 + * @param 节点类型 + */ + private static void setChildren(E root, List nodes, Map filterOperated, Function idFunc, Function parentIdFunc, BiConsumer> setChildFunc) { + List children = new ArrayList<>(); + nodes.stream() + //过滤出未操作过的节点 + .filter(body -> !filterOperated.containsKey(idFunc.apply(body))) + //过滤出孩子节点 + .filter(body -> Objects.equals(idFunc.apply(root), parentIdFunc.apply(body))) + .forEach(body -> { + filterOperated.put(idFunc.apply(body), idFunc.apply(root)); + children.add(body); + //递归 对每个孩子节点执行同样操作 + setChildren(body, nodes, filterOperated, idFunc, parentIdFunc, setChildFunc); + }); + setChildFunc.accept(root, children); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeTest.java index d4db2ec8e..224f37c3e 100755 --- a/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/tree/TreeTest.java @@ -1,6 +1,7 @@ package cn.hutool.core.lang.tree; import cn.hutool.core.collection.CollUtil; +import lombok.Data; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -122,4 +123,39 @@ public class TreeTest { tree.walk((tr) -> ids2.add(tr.getId())); assertEquals(7, ids2.size()); } + + + @Data + static class Area { + private Integer id; + private String name; + private Integer parentId; + private List childrenList; + + public Area(Integer id, String name, Integer parentId) { + this.id = id; + this.name = name; + this.parentId = parentId; + } + } + // 模拟数据 + static List areaList = CollUtil.newArrayList(); + static { + areaList.add(new Area(1, "中国", 0)); + areaList.add(new Area(2, "北京", 1)); + areaList.add(new Area(3, "上海", 1)); + areaList.add(new Area(4, "广东", 1)); + areaList.add(new Area(5, "广州", 4)); + areaList.add(new Area(6, "深圳", 4)); + areaList.add(new Area(7, "浙江", 1)); + areaList.add(new Area(8, "杭州", 7)); + } + + @Test + public void builderTest() { + List list = TreeUtil.build(areaList, 0, Area::getId, Area::getParentId, Area::setChildrenList); + final Area root = list.get(0); + final Integer parentId = root.getChildrenList().get(0).getParentId(); + assertEquals(root.getId(), parentId); + } }