java8 list to tree 工具类

127 阅读1分钟

ListToTreeUtil

import lombok.Data;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

public class ListToTreeUtil {


    public static <T> List<Tree<T>> convertListToTree(List<T> nodeList, TreeConverter<T> converter) {
        if (nodeList == null || nodeList.isEmpty()) {
            return new ArrayList<>();
        }

        Map<Object, Tree<T>> nodeMap = new HashMap<>();
        List<Tree<T>> rootNodes = new ArrayList<>();

        // 将节点放入Map中,方便后续查找和创建树
        for (T item : nodeList) {
            Object itemId = converter.getItemId(item);
            Tree<T> treeNode = new Tree<>(itemId, item);
            nodeMap.put(itemId, treeNode);
        }

        // 遍历节点列表,将每个节点添加到其父节点的子节点列表中,或者作为根节点
        for (T item : nodeList) {
            Object parentId = converter.getParentId(item);

            if (parentId == null || !nodeMap.containsKey(parentId)) {
                // 没有父节点,将其视为根节点
                Tree<T> rootNode = nodeMap.get(converter.getItemId(item));
                rootNodes.add(rootNode);
            } else {
                Tree<T> parent = nodeMap.get(parentId);
                Tree<T> childNode = nodeMap.get(converter.getItemId(item));
                parent.addChild(childNode);
            }
        }

        return rootNodes;
    }

    public interface TreeConverter<T> {
        /**
         * 获取节点的唯一标识ID
         *
         * @param item 节点对象
         * @return 节点ID
         */
        Object getItemId(T item);

        /**
         * 获取节点的父节点ID
         *
         * @param item 节点对象
         * @return 父节点ID
         */
        Object getParentId(T item);
    }

    @Data
    public static class Tree<T> {
        private Object id;
        private T data;
        private List<Tree<T>> children;

        public Tree(Object id, T data) {
            this.id = id;
            this.data = data;
            this.children = new ArrayList<>();
        }

        public void addChild(Tree<T> child) {
            children.add(child);
        }
    }


    public static <T> List<T> convertListToTree(List<T> nodeList, TreeIdAccessor<T> idAccessor, TreeParentIdAccessor<T> parentIdAccessor, TreeChildrenAccessor<T>  childrenAccessor, SetChildFunction<T> setChildFunction) {
        if (nodeList == null || nodeList.isEmpty()) {
            return new ArrayList<>();
        }

        Map<Object, T> nodeMap = new HashMap<>();
        List<T> rootNodes = new ArrayList<>();

        // 将节点放入Map中,方便后续查找和创建树
        for (T node : nodeList) {
            Object nodeId = idAccessor.getId(node);
//            Object nodeId = idAccessor.apply(node);
            nodeMap.put(nodeId, node);
        }

        // 遍历节点列表,将每个节点添加到其父节点的子节点列表中,或者作为根节点
        for (T node : nodeList) {
            Object parentId = parentIdAccessor.getParentId(node);
            if (parentId == null) {
                // 没有父节点,将其视为根节点
                rootNodes.add(node);
            } else {
                T parent = nodeMap.get(parentId);
                if (parent != null) {
                    List<T> children = childrenAccessor.getChildren(parent);
//                    List<T> children = childrenAccessor.apply(parent);
                    if (Objects.isNull(children)) {
                        children = new LinkedList<>();
                        setChildFunction.setChildren(parent, children);
//                        setChildFunction.accept(parent,children);
                    }
                    children.add(node);
                } else {
                    // 父节点不存在,将当前节点视为根节点
                    rootNodes.add(node);
                }
            }
        }

        return rootNodes;
    }


    public static <T> List<T> convertListToTreeV2(List<T> nodeList, Function<T,Object> idAccessor, Function<T,Object> parentIdAccessor, Function<T,List<T>> childrenAccessor, BiConsumer<T,List<T>> setChildFunction) {
        if (nodeList == null || nodeList.isEmpty()) {
            return new ArrayList<>();
        }

        Map<Object, T> nodeMap = new HashMap<>();
        List<T> rootNodes = new ArrayList<>();

        // 将节点放入Map中,方便后续查找和创建树
        for (T node : nodeList) {
            Object nodeId = idAccessor.apply(node);
            nodeMap.put(nodeId, node);
        }

        // 遍历节点列表,将每个节点添加到其父节点的子节点列表中,或者作为根节点
        for (T node : nodeList) {
            Object parentId = parentIdAccessor.apply(node);
            if (parentId == null) {
                // 没有父节点,将其视为根节点
                rootNodes.add(node);
            } else {
                T parent = nodeMap.get(parentId);
                if (parent != null) {
                    List<T> children = childrenAccessor.apply(parent);
                    if (Objects.isNull(children)) {
                        children = new LinkedList<>();
                        setChildFunction.accept(parent,children);
                    }
                    children.add(node);
                } else {
                    // 父节点不存在,将当前节点视为根节点
                    rootNodes.add(node);
                }
            }
        }

        return rootNodes;
    }


    /**
     *  标识节点的唯一ID
     *  可以用 {@link java.util.function.Function} 替代  Function<T,Object> idAccessor   Object nodeId = idAccessor.apply(node);
     * @param <T>
     */
    public interface TreeIdAccessor<T> {
        Object getId(T node);
    }

    // 获取节点的父节点ID
    public interface TreeParentIdAccessor<T> {
        Object getParentId(T node);
    }


    /**
     * 获取节点的子节点列表
     * 可以用 {@link java.util.function.Function} 替代  Function<T,List<T>> childrenAccessor   Object nodeId = idAccessor.apply(node);
     * @param <T>
     */
    public interface TreeChildrenAccessor<T> {
        List<T> getChildren(T node);
    }

    /**
     * 设置节点的子节点列表
     * 可以用 {@link java.util.function.BiConsumer} 替代  BiConsumer<T,List<T>> setChildFunction   setChildFunction.accept(parent,children);
     */
    public interface SetChildFunction<T> {
        void setChildren(T node, List<T> childNodeList);
    }
}

测试

import cn.hutool.json.JSONUtil;

import java.util.ArrayList;
import java.util.List;

public class Example {
    public static void main(String[] args) throws Throwable {
        List<Item> itemList = new ArrayList<>();
        itemList.add(new Item("A", null));
        itemList.add(new Item("B", "A"));
        itemList.add(new Item("C", "A"));
        itemList.add(new Item("D", "B"));
        itemList.add(new Item("E", "B"));


        //针对 节点有 List<Item> child 字段 的情况
        System.out.println(JSONUtil.toJsonPrettyStr(ListToTreeUtil.convertListToTree(itemList,
                Item::getNodeName,
                Item::getParentNodeName,
                Item::getChild,
                Item::setChild
        )));

        System.err.println("-----------------------------------------------");

        System.out.println(JSONUtil.toJsonPrettyStr(ListToTreeUtil.convertListToTreeV2(itemList,
                Item::getNodeName,
                Item::getParentNodeName,
                Item::getChild,
                Item::setChild
        )));

        System.err.println("-----------------------------------------------");
        System.out.println();


        //针对 节点 没有 List<Item> child 字段 的情况
        System.out.println(JSONUtil.toJsonPrettyStr(ListToTreeUtil.convertListToTree(itemList, new ListToTreeUtil.TreeConverter<Item>() {
                    @Override
                    public Object getItemId(Item item) {
                        return item.getNodeName();
                    }

                    @Override
                    public Object getParentId(Item item) {
                        return item.getParentNodeName();
                    }
                }
        )));
    }
}

Item

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Item {
    private String  nodeName;
    private String parentNodeName;

    private List<Item> child;

    public Item(String nodeName, String parentNodeName) {
        this.nodeName = nodeName;
        this.parentNodeName = parentNodeName;
    }
}

输出结果:

[
    {
        "nodeName": "A",
        "child": [
            {
                "nodeName": "B",
                "parentNodeName": "A",
                "child": [
                    {
                        "nodeName": "D",
                        "parentNodeName": "B"
                    },
                    {
                        "nodeName": "E",
                        "parentNodeName": "B"
                    }
                ]
            },
            {
                "nodeName": "C",
                "parentNodeName": "A"
            }
        ]
    }
]
[
    {
        "id": "A",
        "data": {
            "nodeName": "A"
        },
        "children": [
            {
                "id": "B",
                "data": {
                    "nodeName": "B",
                    "parentNodeName": "A"
                },
                "children": [
                    {
                        "id": "D",
                        "data": {
                            "nodeName": "D",
                            "parentNodeName": "B"
                        },
                        "children": [
                        ]
                    },
                    {
                        "id": "E",
                        "data": {
                            "nodeName": "E",
                            "parentNodeName": "B"
                        },
                        "children": [
                        ]
                    }
                ]
            },
            {
                "id": "C",
                "data": {
                    "nodeName": "C",
                    "parentNodeName": "A"
                },
                "children": [
                ]
            }
        ]
    }
]