集合与树形结构

一、注解说明生成树形结构

1.1 注解

java 复制代码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TreeId {
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TreeParentId {
}

1.2 树形节点

java 复制代码
@Data
public class WisDepartment {

    private static final long serialVersionUID = 1L;
 
    /**
     * 外部主键id(三方数据id)
     */
    @TreeId
    @FieldMapping(sourceName = {"an_org_id"})
    @TableField("EXTERNAL_ID")
    private String externalId;

    /**
     * 外部主键父Id(三方数据父级id)
     */
    @TreeParentId
    @FieldMapping(sourceName = {"parent_id"})
    @TableField("EXTERNAL_PARENT_ID")
    private String externalParentId;

    /**
     * 部门名称
     */
    @FieldMapping(sourceName = {"org_name"})
    @NotEmpty(message = "部门名称不能为空")
    @Length(max = 64, message = "部门名称长度不能超过64")
    @TableField("NAME")
    private String name;
 
    @TableField(exist = false)
    private List<WisDepartment> children = new ArrayList<>();


}

1.3 树形结构构建工具

java 复制代码
public class TreeBuilder<T> {

    public List<T> buildTree(List<T> nodes) throws Exception {
        if (nodes == null || nodes.isEmpty()) return Collections.emptyList();

        Class<?> clazz = nodes.get(0).getClass();
        Field idField = getFieldWithAnnotation(clazz, TreeId.class);
        Field parentIdField = getFieldWithAnnotation(clazz, TreeParentId.class);
        Field childrenField = getChildrenField(clazz);

        idField.setAccessible(true);
        parentIdField.setAccessible(true);
        if (childrenField != null) childrenField.setAccessible(true);

        // 建立id到node的映射
        Map<Object, T> idMap = new HashMap<>();
        for (T node : nodes) {
            Object id = idField.get(node);
            idMap.put(id, node);
        }

        List<T> roots = new ArrayList<>();
        for (T node : nodes) {
            Object parentId = parentIdField.get(node);
            if (!idMap.containsKey(parentId) || parentId == null || "".equals(parentId)) {
                roots.add(node);
            } else {
                T parent = idMap.get(parentId);
                if (childrenField != null) {
                    List<T> children = (List<T>) childrenField.get(parent);
                    if (children == null) {
                        children = new ArrayList<>();
                        childrenField.set(parent, children);
                    }
                    children.add(node);
                }
            }
        }
        return roots;
    }

    private Field getFieldWithAnnotation(Class<?> clazz, Class<? extends java.lang.annotation.Annotation> anno) {
        for (Field f : clazz.getDeclaredFields()) {
            if (f.isAnnotationPresent(anno)) return f;
        }
        throw new IllegalArgumentException("No field with annotation " + anno);
    }
    private Field getChildrenField(Class<?> clazz) {
        for (Field f : clazz.getDeclaredFields()) {
            if ("children".equals(f.getName())) return f;
        }
        return null;
    }

    /**
     * 集合构建树形结构
     * 1.数据节点,父级id不存在集合中,则需要将父级节点设置为根节点
     * @param nodes
     * @param rootId
     * @return
     */
    public static List<WisDepartment> buildTree(List<WisDepartment> nodes,String rootId) {
        Map<String, WisDepartment> idNodeMap = nodes.stream()
                .collect(Collectors.toMap(WisDepartment::getExternalId, node -> node));

        List<WisDepartment> rootNodes = new ArrayList<>();

        for (WisDepartment node : nodes) {
            if (rootId.equals(node.getExternalParentId())) {
                // 根节点
                rootNodes.add(node);
            } else {
                // 非根,根据parentId 找父节点,然后把自己加入父节点的children
                WisDepartment parent = idNodeMap.get(node.getExternalParentId());
                if (parent != null) {
                    parent.getChildren().add(node);
                }else{
                    node.setExternalParentId(rootId);
                    rootNodes.add(node);
                }
            }
        }

        return rootNodes;
    }

    public static void main(String[] args) throws Exception {
        List<WisDepartment> departments = JSONArray.parseArray(ss,WisDepartment.class);
        System.out.println("data1: "+ JSONObject.toJSONString(departments));
        String  rootId = "20221206140844614-6ECD-5B3376E42";
        TreeBuilder<WisDepartment> builder = new TreeBuilder<>();
//        List<WisDepartment>  tree =  builder.buildTree(departments);
        List<WisDepartment>  tree2 =  builder.buildTree(departments,rootId);

//
//
//        List<WisDepartment> collect = departments.stream().filter(m -> m.getExternalParentId().equals(rootId)).map(
//                (m) -> {
//                    m.setChildren(getChildrenList(m, departments));
//                    return m;
//                }
//        ).collect(Collectors.toList());
//        System.out.println(JSONObject.toJSONString(collect));
        System.out.println("data2: "+JSONObject.toJSONString(departments));
 
    }


    /**
     * 获取子节点列表
     * @param tree
     * @param list
     * @return
     */
    public static List<WisDepartment> getChildrenList(WisDepartment tree, List<WisDepartment> list){
        List<WisDepartment> children = list.stream().filter(item -> item.getExternalParentId().equals( tree.getExternalId())).map(
                (item) -> {
                    item.setChildren(getChildrenList(item, list));
                    return item;
                }
        ).collect(Collectors.toList());
        return children;
    }

    public static String ss = "[\n" +
            "        {\n" +
            "            \"an_org_id\": \"an001\",\n" +
            "            \"externalId\": \"an001\",\n" +
            "            \"parent_id\": \"20221206140844614-6ECD-5B3376E42\",\n" +
            "            \"externalParentId\": \"20221206140844614-6ECD-5B3376E42\",\n" +
            "            \"path\": \"父组织路径\",\n" +
            "            \"path_name\": \"组织全路径名称\",\n" +
            "            \"org_level\": \"1\",\n" +
            "            \"org_name\": \"an001bbk\",\n" +
            "            \"org_name_abbr\": \"组织简称\",\n" +
            "            \"org_order\": \"1\",\n" +
            "            \"an_org_type\": \"1\",\n" +
            "            \"an_credit_code\": \"xfn40\",\n" +
            "            \"an_legal_person\": \"法定代表人\",\n" +
            "            \"sys_org_code\": \"创建人所属部门\",\n" +
            "            \"org_is_disabled\": \"0\",\n" +
            "            \"postal_address\": \"通讯地址(公司/基地)\",\n" +
            "            \"charge_project_name\": \"项目部负责人\"\n" +
            "        }, \n" +
            "\t\t{\n" +
            "            \"an_org_id\": \"an002\",\n" +
            "            \"externalId\": \"an002\",\n" +
            "            \"parent_id\": \"20221206140844614-6ECD-5B3376E42\",\n" +
            "            \"externalParentId\": \"20221206140844614-6ECD-5B3376E42\",\n" +
            "            \"path\": \"父组织路径\",\n" +
            "            \"path_name\": \"组织全路径名称\",\n" +
            "            \"org_level\": \"1\",\n" +
            "            \"org_name\": \"an002\",\n" +
            "            \"org_name_abbr\": \"组织简称\",\n" +
            "            \"org_order\": \"2\",\n" +
            "            \"an_org_type\": \"1\",\n" +
            "            \"an_credit_code\": \"xfn40\",\n" +
            "            \"an_legal_person\": \"法定代表人\",\n" +
            "            \"sys_org_code\": \"创建人所属部门\",\n" +
            "            \"org_is_disabled\": \"0\",\n" +
            "            \"postal_address\": \"通讯地址(公司/基地)\",\n" +
            "            \"charge_project_name\": \"项目部负责人\"\n" +
            "        }, \n" +
            "\t\t{\n" +
            "            \"an_org_id\": \"an001001\",\n" +
            "            \"externalId\": \"an001001\",\n" +
            "            \"parent_id\": \"an002\",\n" +
            "            \"externalParentId\": \"an002\",\n" +
            "            \"path\": \"父组织路径\",\n" +
            "            \"path_name\": \"组织全路径名称\",\n" +
            "            \"org_level\": \"1\",\n" +
            "            \"org_name\": \"an001001\",\n" +
            "            \"org_name_abbr\": \"组织简称\",\n" +
            "            \"org_order\": \"1\",\n" +
            "            \"an_org_type\": \"1\",\n" +
            "            \"an_credit_code\": \"xfn40\",\n" +
            "            \"an_legal_person\": \"法定代表人/负责人\",\n" +
            "            \"sys_org_code\": \"创建人所属部门\",\n" +
            "            \"org_is_disabled\": \"0\",\n" +
            "            \"postal_address\": \"通讯地址(公司/基地)\",\n" +
            "            \"charge_project_name\": \"项目部负责人\"\n" +
            "        }\n" +
            "\t\t, \n" +
            "\t\t{\n" +
            "            \"an_org_id\": \"an003\",\n" +
            "            \"externalId\": \"an003\",\n" +
            "            \"parent_id\": \"an003\",\n" +
            "            \"externalParentId\": \"an0039\",\n" +
            "            \"path\": \"父组织路径\",\n" +
            "            \"path_name\": \"组织全路径名称\",\n" +
            "            \"org_level\": \"1\",\n" +
            "            \"org_name\": \"an003\",\n" +
            "            \"org_name_abbr\": \"组织简称\",\n" +
            "            \"org_order\": \"1\",\n" +
            "            \"an_org_type\": \"1\",\n" +
            "            \"an_credit_code\": \"xfn40\",\n" +
            "            \"an_legal_person\": \"法定代表人/负责人\",\n" +
            "            \"sys_org_code\": \"创建人所属部门\",\n" +
            "            \"org_is_disabled\": \"0\",\n" +
            "            \"postal_address\": \"通讯地址(公司/基地)\",\n" +
            "            \"charge_project_name\": \"项目部负责人\"\n" +
            "        }\n" +
            "    ]";
}
相关推荐
该怎么办呢2 小时前
Source/Core/DeveloperError.js
开发语言·javascript·ecmascript
小璐资源网2 小时前
Java 21 新特性实战:虚拟线程详解
java·开发语言·python
m0_569881472 小时前
基于C++的数据库连接池
开发语言·c++·算法
.select.2 小时前
c++ auto
开发语言·c++·算法
2401_884563242 小时前
C++中的访问者模式高级应用
开发语言·c++·算法
消失的旧时光-19432 小时前
C++ 多态核心三件套:虚函数、纯虚函数、虚析构函数(面试 + 工程完全指南)
开发语言·c++·面试·虚函数·纯虚函数·虚析构函数
青春易逝丶2 小时前
策略模式
java·开发语言·策略模式
freexyn2 小时前
Matlab入门自学七十四:坐标系转换,直角坐标、极坐标和球坐标的转换
开发语言·算法·matlab
柯儿的天空3 小时前
【OpenClaw 全面解析:从零到精通】第 006 篇:OpenClaw 在 Windows/WSL2 上的安装与部署实战
人工智能·windows·语言模型·chatgpt·ai作画