All Downloads are FREE. Search and download functionalities are using the official Maven repository.

shz.core.model.TreeNode Maven / Gradle / Ivy

There is a newer version: 10.3.1
Show newest version
package shz.core.model;

import shz.core.NullHelp;
import shz.core.ToList;
import shz.core.ToMap;

import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * 树结构节点
 */
@SuppressWarnings("unchecked")
public class TreeNode> {
    protected ID id;
    protected List childes;

    public final int count(Function func) {
        Integer apply = func.apply((T) this);
        int count = apply == null ? 0 : apply;
        if (NullHelp.isEmpty(childes)) return count;
        for (T t : childes) count += t.count(func);
        return count;
    }

    public final int count() {
        return count(t -> 1);
    }

    public final int leafCount() {
        if (NullHelp.isEmpty(childes)) return 1;
        int count = 0;
        for (T t : childes) count += t.leafCount();
        return count;
    }

    @SafeVarargs
    public final  List spread(Function firstMapper, BiFunction... mappers) {
        R r = firstMapper.apply((T) this);
        if (r == null) return Collections.emptyList();
        if (NullHelp.isEmpty(mappers) || NullHelp.isEmpty(childes)) return Collections.singletonList(r);
        List result = new ArrayList<>(leafCount());
        for (T t : childes) t.spread(result, r, 0, mappers);
        return result;
    }

    @SafeVarargs
    final  void spread(List result, R r, int level, BiFunction... mappers) {
        if (level == mappers.length || NullHelp.isEmpty(childes)) {
            result.add(r);
            return;
        }
        for (T t : childes) t.spread(result, mappers[level].apply(r, t), level + 1, mappers);
    }

    public ID getId() {
        return id;
    }

    public void setId(ID id) {
        this.id = id;
    }

    public List getChildes() {
        return childes;
    }

    public void setChildes(List childes) {
        this.childes = childes;
    }

    @Override
    public String toString() {
        return "TreeNode{" +
                "id=" + id +
                ", childes=" + childes +
                '}';
    }

    /**
     * 获取分组树
     *
     * @param list          需要分组的数据
     * @param mapper        数据映射器
     * @param lastMapper    最后分组数据映射器
     * @param lastCollector 最后分组数据收集器
     * @param classifiers   分组函数集
     */
    @SafeVarargs
    public static , R> List group(List list, BiFunction, T> mapper,
                                                                    BiFunction lastMapper,
                                                                    Collector lastCollector,
                                                                    Function... classifiers) {
        if (NullHelp.isEmpty(list)) return Collections.emptyList();
        Collector> collector = Collectors.groupingBy(classifiers[classifiers.length - 1], lastCollector);
        for (int i = classifiers.length - 2; i >= 0; --i) collector = Collectors.groupingBy(classifiers[i], collector);
        return mergeGroup(list.stream().collect(collector), mapper, lastMapper);
    }

    private static , R> List mergeGroup(Map group, BiFunction, T> mapper, BiFunction lastMapper) {
        return ToList.explicitCollect(group.keySet().stream().map(k -> {
            Object nextGroup = group.get(k);
            return nextGroup instanceof Map
                    ? mapper.apply(k, mergeGroup((Map) nextGroup, mapper, lastMapper))
                    : lastMapper.apply(k, (R) nextGroup);
        }), group.size());
    }

    /**
     * 获取分组树
     *
     * @param list       需要分组的数据
     * @param classifier 分类函数
     * @param mapper     数据映射器
     * @param nullMapper 空节点映射器
     */
    public static > List group(List list, Function classifier, BiFunction mapper, Function nullMapper) {
        if (NullHelp.isEmpty(list)) return Collections.emptyList();
        Map> rootMap = new LinkedHashMap<>();
        Map> levelChildesMap = new HashMap<>();
        for (E e : list) {
            if (e == null) continue;
            String[] classifiers = classifier.apply(e);
            int level = classifiers.length;
            T t = mapper.apply(e, classifiers[level - 1]);
            if (level == 1) rootMap.put(classifiers[0], new MapTreeNode<>(t));
            else {
                Map childesMap = levelChildesMap.computeIfAbsent(level, k -> new LinkedHashMap<>());
                childesMap.put(t, classifiers);
            }
        }

        int level = 1;
        while (!levelChildesMap.isEmpty()) {
            Map tMap = levelChildesMap.get(++level);
            if (tMap == null) continue;

            tMap.forEach((t, classifiers) -> {
                MapTreeNode root = rootMap.get(classifiers[0]);
                if (root == null) {
                    root = new MapTreeNode<>(nullMapper.apply(classifiers[0]));
                    root.childes = new LinkedHashMap<>();
                    rootMap.put(classifiers[0], root);
                }

                int limit = classifiers.length - 1;
                MapTreeNode parent = root;
                for (int i = 1; i < limit; ++i) {
                    MapTreeNode child = parent.childes.get(classifiers[i]);
                    if (child == null) {
                        child = new MapTreeNode<>(nullMapper.apply(classifiers[i]));
                        child.childes = new LinkedHashMap<>();
                        parent.childes.put(classifiers[i], child);
                    }
                    parent = child;
                }

                parent.childes.put(classifiers[limit], new MapTreeNode<>(t));
            });

            levelChildesMap.remove(level);
        }

        return ToList.explicitCollect(rootMap.values().stream().map(MapTreeNode::data), rootMap.size());
    }

    private static final class MapTreeNode> {
        T data;
        Map> childes;

        MapTreeNode(T data) {
            this.data = data;
        }

        T data() {
            if (childes != null)
                data.setChildes(ToList.explicitCollect(childes.values().stream().map(MapTreeNode::data), childes.size()));
            return data;
        }
    }

    /**
     * 排序分组树
     */
    public static > void sort(List nodes, Comparator comparator) {
        if (NullHelp.isEmpty(nodes)) return;
        nodes.sort(comparator);
        nodes.forEach(node -> sort(node.getChildes(), comparator));
    }

    /**
     * 合并分组树
     */
    public static > List merge(List nodes, List otherNodes, BiFunction merger) {
        if (NullHelp.isEmpty(nodes))
            return otherNodes == null || otherNodes.isEmpty() ? Collections.emptyList() : otherNodes;
        if (NullHelp.isEmpty(otherNodes)) return nodes;
        Map map = ToMap.collect(nodes.stream(), TreeNode::getId, Function.identity());
        Map otherMap = ToMap.collect(otherNodes.stream(), TreeNode::getId, Function.identity());
        Set ids = new HashSet<>(map.keySet());
        Set otherIds = new HashSet<>(otherMap.keySet());
        if (!otherIds.removeAll(ids) || !otherIds.isEmpty()) ids.addAll(otherIds);
        return ToList.explicitCollect(ids.stream().map(k -> {
            T t = map.get(k);
            T other = otherMap.get(k);
            if (t == null) return other;
            else if (other == null) return t;
            T result = merger.apply(t, other);
            result.setChildes(merge(t.getChildes(), other.getChildes(), merger));
            return result;
        }), ids.size());
    }
}