一个自动组装树结构数据的工具类

这个一个可以将任何存在上下级关系的数据组装成普通树形结构的工具类,可以在不改变原始数据结构的情况下处理原始数据的树形关系。


import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

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

public class TreeUtils {
    private TreeUtils() {
        throw new IllegalStateException("Utility class");
    }

    /**
     * 变换列表
     *
     * @param collection 收藏
     * @return {@link List}<{@link R}>
     */
    public static <T, R extends TreeInterface<T>> List<R> transformList(Collection<R> collection) {
        if (CollectionUtils.isEmpty(collection)) {
            return new ArrayList<>();
        }
        List<R> result = new ArrayList<>();
        Stack<R> stack = new Stack<>();
        stack.addAll(collection);
        while (!stack.isEmpty()) {
            R pop = stack.pop();
            result.add(pop);
            if (!CollectionUtils.isEmpty(pop.getChildren())) {
                stack.addAll(pop.getChildren());
            }
        }
        return result;
    }

    /**
     * 变换列表
     *
     * @param collection 收藏
     * @param consumer   消费者
     */
    public static <T, R extends TreeInterface<T>> void transformList(Collection<R> collection, Consumer<R> consumer) {
        if (CollectionUtils.isEmpty(collection)) {
            return;
        }
        Stack<R> stack = new Stack<>();
        stack.addAll(collection);
        while (!stack.isEmpty()) {
            R pop = stack.pop();
            consumer.accept(pop);
            if (!CollectionUtils.isEmpty(pop.getChildren())) {
                stack.addAll(pop.getChildren());
            }
        }
    }

    /**
     * 获取树
     *
     * @param collection 收藏
     * @return {@link List}<{@link TreeDefault}<{@link T}>>
     */
    public static <T> List<TreeDefault<T>> getTree(Collection<TreeParam<T>> collection) {
        return getTree(collection, () -> TreeDefault.<T>builder().build());
    }


    /**
     * 获取树
     *
     * @param collection 收藏
     * @param clazz      克拉兹
     * @return {@link List}<{@link R}>
     */
    public static <T, R extends TreeInterface<T>> List<R> getTree(Collection<TreeParam<T>> collection,
                                                                  Class<R> clazz) {
        return getTree(collection, () -> getNewInstance(clazz));
    }

    /**
     * 获取树
     *
     * @param collection 收藏
     * @param supplier   供应商
     * @return {@link List}<{@link R}>
     */
    public static <T, R extends TreeInterface<T>> List<R> getTree(Collection<TreeParam<T>> collection,
                                                                  Supplier<R> supplier) {
        if (CollectionUtils.isEmpty(collection)) {
            return null;
        }
        Map<String, Set<String>> node = new HashMap<>();//记录节点关系
        Map<String, List<T>> nodeParentData = new HashMap<>();//记录节点字段
        Map<String, List<T>> nodeData = new HashMap<>();//记录节点字段
        collection.forEach(item -> {
            String key = item.getKey();
            String nodeParentDataKey = key;
            if (StringUtils.isNotBlank(item.getParentKey())) {
                nodeParentDataKey = key + item.getParentKey();
            }
            List<T> values = nodeParentData.computeIfAbsent(nodeParentDataKey, k -> new ArrayList<>());
            values.add(item.getData());
            List<T> nodeDataValues = nodeData.computeIfAbsent(key, k -> new ArrayList<>());
            nodeDataValues.add(item.getData());
            if (StringUtils.isBlank(item.getParentKey())) {//根对象
                node.put(key, null);
            } else {
                Set<String> parents = node.computeIfAbsent(key, k -> new HashSet<>());
                parents.add(item.getParentKey());
            }
        });
        List<R> treeDTO = new ArrayList<>();

        Iterator<Map.Entry<String, Set<String>>> iterator = node.entrySet().iterator();
        //提取根级节点数据
        Set<String> parentIds = new HashSet<>(node.keySet());
        while (iterator.hasNext()) {
            Map.Entry<String, Set<String>> next = iterator.next();
            String key = next.getKey();
            Set<String> value = next.getValue();
            if (value == null || value.stream().noneMatch(parentIds::contains)) {
                List<T> data = nodeParentData.get(key);
                if (data == null) {
                    data = nodeData.get(key);
                }
                Optional.ofNullable(data).orElse(new ArrayList<>())
                        .forEach(item -> {
                            R instance = supplier.get();
                            instance.setNode(key);
                            instance.setData(item);
                            treeDTO.add(instance);
                        });
                iterator.remove();
            }
        }
        Stack<R> stack = new Stack<>();
        stack.addAll(treeDTO);
        while (!stack.isEmpty()) {
            R pop = stack.pop();
            iterator = node.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Set<String>> next = iterator.next();
                Set<String> value = next.getValue();
                String key = next.getKey();
                if (value.contains(pop.getNode())) {
                    List<T> nodeParentDataValue = nodeParentData.getOrDefault(key + pop.getNode(), new ArrayList<>());
                    nodeParentDataValue.forEach(item -> {
                        R instance = supplier.get();
                        instance.setNode(key);
                        instance.setData(item);
                        stack.push(instance);
                        pop.addChild(instance);
                    });
                    value.remove(pop.getNode());
                    if (value.isEmpty()) {
                        iterator.remove();
                    }
                }
            }
        }
        return treeDTO;
    }

    /**
     * 获取新实例
     *
     * @param clazz 克拉兹
     * @return {@link R}
     */
    private static <T, R extends TreeInterface<T>> R getNewInstance(Class<R> clazz) {
        try {
            return clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}


import lombok.*;

/**
 * 用于获取数据树结构数据时使用的通用参数
 *
 * @param <T> 实际的数据对象类型
 */
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Getter
@Setter
public class TreeParam<T> {
    /**
     * 数据主键
     */
    private String key;
    /**
     * 数据上级主键
     */
    private String parentKey;
    /**
     * 原始数据对象
     */
    private T data;
}

import java.util.List;

public interface TreeInterface<T> {
    String getNode();

    void setNode(String node);

    T getData();

    void setData(T data);

    <R extends TreeInterface<T>> R getParent();

    void setParent(TreeInterface<T> parent);

    <R extends TreeInterface<T>> List<R> getChildren();

    /**
     * 添加孩子
     *
     * @param child 孩子
     */
    void addChild(TreeInterface<T> child);

    /**
     * 等级
     *
     * @return int
     */
    default int level() {
        if (getParent() == null) {
            return 0;
        } else {
            return getParent().level() + 1;
        }
    }
}

import lombok.*;

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

/**
 * 树默认值
 *
 * @author jm
 * @date 2024/02/17
 */
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TreeDefault<T> implements TreeInterface<T> {
    @Setter
    private String node;
    @Setter
    private T data;
    private TreeDefault<T> parent;
    private List<TreeDefault<T>> children;

    @Override
    public void setParent(TreeInterface<T> parent) {
        if (parent != null && TreeDefault.class.isAssignableFrom(parent.getClass())) {
            this.parent = (TreeDefault<T>) parent;
        }
    }

    @Override
    public void addChild(TreeInterface<T> child) {
        if (child != null && TreeDefault.class.isAssignableFrom(child.getClass())) {
            TreeDefault<T> childDTO = (TreeDefault<T>) child;
            if (children == null) {
                children = new ArrayList<>();
            }
            child.setParent(this);
            children.add(childDTO);
        }
    }
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值