java - listmap组装树形结构

package cn.seaboot.commons.core;

import cn.seaboot.commons.exception.BizException;
import cn.seaboot.commons.lang.Warning;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 数据组装树形结构(Map版本)
 *
 * @author Mr.css
 * @version 2020-07-06 11:18
 */
public class TreeBuilder {
    private List<Map<String, Object>> parent;
    private List<Map<String, Object>> child;
    private String idField = "id";
    private String pidField = "pid";
    private String childrenField = "children";


    public List<Map<String, Object>> getParent() {
        return parent;
    }

    public TreeBuilder setParent(List<Map<String, Object>> parent) {
        this.parent = parent;
        return this;
    }

    public List<Map<String, Object>> getChild() {
        return child;
    }

    public TreeBuilder setChild(List<Map<String, Object>> child) {
        this.child = child;
        return this;
    }

    public TreeBuilder setIdField(String idField) {
        this.idField = idField;
        return this;
    }

    public TreeBuilder setPidField(String pidField) {
        this.pidField = pidField;
        return this;
    }

    public TreeBuilder setChildrenField(String childrenField) {
        this.childrenField = childrenField;
        return this;
    }

    /**
     * 数据分组
     *
     * @return TreeBuilder
     */
    @SuppressWarnings(Warning.UNCHECKED)
    public TreeBuilder groupBy() {
        if (child == null) {
            child = parent;
        }
        for (Map<String, Object> p : parent) {
            for (Map<String, Object> c : child) {
                if (p.get(this.idField).equals(c.get(this.pidField))) {
                    List<Map<String, Object>> list = (List<Map<String, Object>>) p.get(this.childrenField);
                    if (list == null) {
                        list = new ArrayList<>();
                        p.put(this.childrenField, list);
                    }
                    list.add(c);
                }
            }
        }
        return this;
    }

    /**
     * 如果已知要取的节点,直接按照节点pId进行获取
     *
     * @return tree
     */
    public List<Map<String, Object>> getByPid(@Nullable Object pidValue) {
        List<Map<String, Object>> res = new ArrayList<>();
        if (pidValue == null) {
            for (Map<String, Object> p : parent) {
                if (p.get(pidField) == null) {
                    res.add(p);
                }
            }
        } else {
            for (Map<String, Object> p : parent) {
                if (p.get(pidField).equals(pidValue)) {
                    res.add(p);
                }
            }
        }
        return res;
    }

    /**
     * 从组装的结果中取出Pid最小的数据
     *
     * @return tree
     */
    @SuppressWarnings({Warning.UNCHECKED, Warning.RAW_TYPES})
    public List<Map<String, Object>> getByMinPid() {
        Comparable min = (Comparable) parent.get(0).get(pidField);
        Comparable obj;
        for (Map<String, Object> p : parent) {
            obj = (Comparable) p.get(pidField);
            if (obj.compareTo(min) < 0) {
                min = obj;
            }
        }
        return this.getByPid(min);
    }

    /**
     * 从组装的结果中取出Pid最大的数据
     *
     * @return tree
     * @throws ClassCastException List元素未继承自Comparable接口
     */
    @SuppressWarnings({Warning.UNCHECKED, Warning.RAW_TYPES})
    public List<Map<String, Object>> getByMaxPid() {
        Comparable max = (Comparable) parent.get(0).get(pidField);
        Comparable obj;
        for (Map<String, Object> p : parent) {
            obj = (Comparable) p.get(pidField);
            if (obj.compareTo(max) > 0) {
                max = obj;
            }
        }
        return this.getByPid(max);
    }

    /**
     * 随机取出一个元素,反复遍历树,直到取出最顶级的父节点
     *
     * @return tree
     * @throws ClassCastException List元素未继承自Comparable接口
     */
    @SuppressWarnings({Warning.UNCHECKED, Warning.RAW_TYPES})
    public List<Map<String, Object>> getRoot() {
        // 存在 pid 为 null 的数据
        for (Map<String, Object> p : parent) {
            if (p.get(pidField) == null) {
                return this.getByPid(null);
            }
        }

        Comparable max = (Comparable) parent.get(0).get(pidField);

        // 已经查找过的节点
        List<Comparable> list = new ArrayList<>();
        while (true) {
            // 查找更大的父节点
            Comparable pid = null;
            for (Map<String, Object> p : parent) {
                if (max.compareTo(p.get(idField)) == 0) {
                    pid = (Comparable) p.get(pidField);
                    break;
                }
            }

            if (pid == null) {
                // 找不到更大的节点,与 for 循环中的空值判断含义不同
                return this.getByPid(max);
            } else {
                max = pid;
                // 判断是否发生循环依赖,不然会发生无线循环
                if (list.contains(max)) {
                    throw new BizException("Circular dependencies");
                } else {
                    list.add(max);
                }
            }
        }
    }
}


posted on   疯狂的妞妞  阅读(661)  评论(0编辑  收藏  举报

(评论功能已被禁用)
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示