Java 树形结构工具类

一、定义接口,统一规范

/**
 * 树形结构基础接口
 */
public interface TreeNodeBase<T> {
    /**
     * @return 获取当前元素Id
     */
    Object getId();

    /**
     * @return 获取父元素Id
     */
    Object getParentId();

    /**
     * @return 获取当前元素的 children 属性
     */
    List<T> getChildren();

}

二、编写工具类 TreeNodeUtil

/**
 * 树形结构工具类
 */
public class TreeNodeUtil {

    public static final String PARENT_NAME = "parent";

    public static final String CHILDREN_NAME = "children";

    /**
     * 根节点ID,默认为0
     */
    public static final List<Object> ROOT_NODE_IDS = Collections.singletonList(0l);



    /**
     * 数据集合构建成树形结构
     *
     * @param dataList 数据集合
     * @return
     */
    public static <T extends TreeNodeBase> List<T> buildTree(List<T> dataList) {
        return buildTree(dataList, ROOT_NODE_IDS, (data) -> data, (item) -> true);
    }

    /**
     * 数据集合构建成树形结构
     *
     * @param dataList 数据集合
     * @param map 调用者提供 Function<T, T> ,可对数据进行操作
     * @return
     */
    public static <T extends TreeNodeBase> List<T> buildTree(List<T> dataList, Function<T, T> map) {
        return buildTree(dataList, ROOT_NODE_IDS, map, (item) -> true);
    }

    /**
     * 数据集合构建成树形结构
     *
     * @param dataList 数据集合
     * @param filter 调用者提供 Predicate<T> 用于数据过滤
     * @return
     */
    public static <T extends TreeNodeBase> List<T> buildTree(List<T> dataList, Predicate<T> filter) {
        return buildTree(dataList, ROOT_NODE_IDS, (data) -> data, filter);
    }

    /**
     * 数据集合构建成树形结构
     *
     * @param dataList 数据集合
     * @param map 调用者提供 Function<T, T> ,可对数据进行操作
     * @param filter 调用者提供 Predicate<T> 用于数据过滤
     * @return
     */
    public static <T extends TreeNodeBase> List<T> buildTree(List<T> dataList, Function<T, T> map, Predicate<T> filter) {
        return buildTree(dataList, ROOT_NODE_IDS, map, filter);
    }

    /**
     * 数据集合构建成树形结构
     *
     * @param dataList 数据集合
     * @param rootIds 初始节点的 Id 集合
     * @return
     */
    public static <T extends TreeNodeBase> List<T> buildTree(List<T> dataList, List<Object> rootIds) {
        return buildTree(dataList, rootIds,(data) -> data, (item) -> true);
    }

    /**
     * 数据集合构建成树形结构
     *
     * @param dataList 数据集合
     * @param rootIds 初始节点的 Id 集合
     * @param map 调用者提供 Function<T, T> ,可对数据进行操作
     * @return
     */
    public static <T extends TreeNodeBase> List<T> buildTree(List<T> dataList, List<Object> rootIds, Function<T, T> map) {
        return buildTree(dataList, rootIds, map, (item) -> true);
    }
    /**
     * 数据集合构建成树形结构
     *
     * @param dataList 数据集合
     * @param rootIds 初始节点的 Id 集合
     * @param filter 调用者提供 Predicate<T> 用于数据过滤
     * @return
     */
    public static <T extends TreeNodeBase> List<T> buildTree(List<T> dataList, List<Object> rootIds, Predicate<T> filter) {
        return buildTree(dataList, rootIds, (data) -> data, filter);
    }



    /**
     * 数据集合构建成树形结构 ( 注: 如果最开始的 ids 不在 dataList 中,不会进行任何处理 )
     *
     * @param dataList 数据集合
     * @param rootIds 初始节点的 Id 集合
     * @param map 调用者提供 Function<T, T> ,可对数据进行操作
     * @param filter 调用者提供 Predicate<T> 用于数据过滤
     * @return
     */
    public static <T extends TreeNodeBase> List<T> buildTree(List<T> dataList, List<Object> rootIds, Function<T, T> map, Predicate<T> filter) {
        if(map==null){
            //对数据进行操作的方法为null时提供默认方法
            map = (data)->data;
        }
        if(filter==null){
            //对数据进行过滤的方法为null时提供默认方法
            filter = (data)->true;
        }
        if (CollectionUtils.isEmpty(rootIds)) {
            return Collections.emptyList();
        }
        // 1. 将数据分为 父子结构
        Map<String, List<T>> nodeMap = dataList.stream()
                .filter(filter)
                .collect(Collectors.groupingBy(item -> rootIds.contains(item.getParentId()) ? PARENT_NAME : CHILDREN_NAME));

        List<T> parent = nodeMap.getOrDefault(PARENT_NAME, Collections.emptyList());
        List<T> children = nodeMap.getOrDefault(CHILDREN_NAME, Collections.emptyList());
        // 1.1 如果未分出或过滤了父元素则将子元素返回
        if (parent.size() == 0) {
            return Collections.emptyList();
        }
        // 2. 存储下一次处理的父节点ids
        List<Object> nextIds = new ArrayList<>(dataList.size());
        // 3. 遍历父元素 以及修元素内容
        List<T> collectParent = parent.stream().map(map).collect(Collectors.toList());
        for (T parentItem : collectParent) {
            // 3.1 如果子元素已经加完,直接进入下一轮循环
            if (nextIds.size() == children.size()) {
                break;
            }
            // 3.2 过滤出 parent.id == children.parentId 的元素
            children.stream()
                    .filter(childrenItem -> parentItem.getId().equals(childrenItem.getParentId()))
                    .forEach(childrenItem -> {
                        // 3.3 这次的子元素为下一次的父元素
                        nextIds.add(childrenItem.getParentId());
                        // 3.4 添加子元素到 parentItem.children 中
                        parentItem.getChildren().add(childrenItem);
                    });
        }
        buildTree(children, nextIds, map, filter);
        return parent;
    }

}

三、测试

/**
 * 树形结构测试
 */
@Data
public class TreeNodeDemo implements TreeNodeBase<TreeNodeDemo> {
    private Long id;

    private String name;


    private Long parentId;

    public TreeNodeDemo(Long id, String name, Long parentId) {
        this.id = id;
        this.name = name;
        this.parentId = parentId;
    }

    private List<TreeNodeDemo> children = new ArrayList<>();


    public static void main(String[] args) {
        List<TreeNodeDemo> testChildren = new ArrayList<>();
        testChildren.add(new TreeNodeDemo(1L, "父元素",  0L));
        testChildren.add(new TreeNodeDemo(2L, "子元素1",  1L));
        testChildren.add(new TreeNodeDemo(3L, "子元素2",  1L));
        testChildren.add(new TreeNodeDemo(4L, "子元素2的孙子元素",  3L));

        //默认根节点id为0开始构建树形结构
        System.out.println(JSON.toJSONString(TreeNodeUtil.buildTree(testChildren)));
        // //默认根节点id为0开始构建树形结构,并对符合要求的数据进行操作
        // System.out.println(JSON.toJSONString(TreeNodeUtil.buildTree(testChildren,(Function<TreeNodeDemo,TreeNodeDemo>)item->{
        //     if (item.getId().equals(1L)) {
        //         item.setName("更改了 Id 为 1L 的数据名称");
        //     }
        //     return item;
        // })));
        // //设置从根节点ID为1开始构建树形结构
        // System.out.println(JSON.toJSONString(TreeNodeUtil.buildTree(testChildren, Collections.singletonList(1L))));
        // //设置根节点ID为1开始构建树形结构并过滤父id为3的元素
        // System.out.println(JSON.toJSONString(TreeNodeUtil.buildTree(testChildren, Collections.singletonList(1L), (Predicate<TreeNodeDemo>) item -> Long.valueOf(3).equals(item.getParentId()))));
    }

}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个 Java 工具类,可以将树形结构数据输出为字符串: ```java import java.util.List; public class TreePrinter { private static final String LINE_PREFIX = " "; private static final String BRANCH_PREFIX = "│ "; private static final String LAST_BRANCH_PREFIX = "└── "; public static <T extends TreeNode> String printTree(T root) { StringBuilder sb = new StringBuilder(); printNode(sb, "", root, true); return sb.toString(); } private static <T extends TreeNode> void printNode(StringBuilder sb, String prefix, T node, boolean isLast) { sb.append(prefix); if (isLast) { sb.append(LAST_BRANCH_PREFIX); prefix += LINE_PREFIX; } else { sb.append(BRANCH_PREFIX); prefix += BRANCH_PREFIX; } sb.append(node.getName()); sb.append("\n"); List<T> children = node.getChildren(); if (children != null) { int size = children.size(); for (int i = 0; i < size; i++) { boolean last = i == size - 1; printNode(sb, prefix, children.get(i), last); } } } public interface TreeNode { String getName(); List<? extends TreeNode> getChildren(); } } ``` 使用方法: 1. 实现 `TreeNode` 接口,并实现其中的两个方法 `getName()` 和 `getChildren()`,分别返回节点名称和子节点列表。 2. 调用 `TreePrinter.printTree(root)` 方法,其中 `root` 为树的根节点。 以下是一个简单的例子: ```java import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) { TreeNode root = new Node("root"); Node node1 = new Node("node1"); Node node2 = new Node("node2"); Node node3 = new Node("node3"); Node node4 = new Node("node4"); Node node5 = new Node("node5"); Node node6 = new Node("node6"); root.addChild(node1); root.addChild(node2); root.addChild(node3); node2.addChild(node4); node2.addChild(node5); node3.addChild(node6); String tree = TreePrinter.printTree(root); System.out.println(tree); } static class Node implements TreePrinter.TreeNode { private String name; private List<Node> children; public Node(String name) { this.name = name; this.children = new ArrayList<>(); } public void addChild(Node child) { children.add(child); } @Override public String getName() { return name; } @Override public List<Node> getChildren() { return children; } } } ``` 输出结果为: ``` └── root ├── node1 ├── node2 │ ├── node4 │ └── node5 └── node3 └── node6 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值