@Data
public class BaseTree<T extends BaseTree<T>> {
private static final long serialVersionUID = 1L;
@TableId(value = "id",type = IdType.AUTO)
private Long id;
private Long parentId;
@TableField(exist = false)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<T> children = new ArrayList<>();
public BaseTree() {}
/**
* 注意:children一定要new ArrayList<>();不然add会报错的
* 核心思想就是先拿出list中所有的parentId,再拿出所有id,做差集 拿到的就是一级类目 这里对parentCode为空的数据赋了0值, 如果是固定值可以直接filter 0的数据
* 递归一级类目下的二级类目,再递归二级类目下的三级类目。。。然后把查到的相应子类目加入到父节点中
*/
public static <T extends BaseTree<T>> List<T> listToTree(List<T> list) {
list.forEach(item->{
if(StringUtils.isBlank(item.getParentCode())){
item.setParentCode("0");
}
});
Set<Long> parentIds = list.stream().map(BaseTree::getParentId).collect(Collectors.toSet());
Set<Long> ids = list.stream().map(BaseTree::getId).collect(Collectors.toSet());
parentIds.removeAll(ids);
// 我这里可以直接用这个
// Set<String> parentIds = list.stream().filter(item->item.getParentCode().equals("0")).map(Category::getParentCode).collect(Collectors.toSet());
//递归查找子结点
return list.stream()
.filter(tree -> parentIds.contains(tree.getParentId()))
.map(tree -> findChildren(tree, list))
.collect(Collectors.toList());
}
private static <T extends BaseTree<T>> T findChildren(T tree, List<T> list) {
list.stream()
.filter(node -> node.getParentId().equals(tree.getId()))
.map(node -> findChildren(node, list))
.forEachOrdered(children -> tree.getChildren().add(children));
return tree;
}
}
也可以直接写在所在类的方法中
public List<BasMallCatalogDTO> listToTree(List<BasMallCatalogDTO> list) {
list.forEach(item->{
if(StringUtils.isBlank(item.getParentCode())){
item.setParentCode("0");
}
});
Set<Long> parentIds = list.stream().map(BasMallCatalogDTO::getParentId).collect(Collectors.toSet());
Set<Long> ids = list.stream().map(BasMallCatalogDTO::getId).collect(Collectors.toSet());
parentIds.removeAll(ids);
// 我这里可以直接用这个
// Set<String> parentIds = list.stream().filter(item->item.getParentCode().equals("0")).map(Category::getParentCode).collect(Collectors.toSet());
//递归查找子结点
return list.stream()
.filter(tree -> parentIds.contains(tree.getParentId()))
.map(tree -> findChildren(tree, list))
.collect(Collectors.toList());
}
private BasMallCatalogDTO findChildren(BasMallCatalogDTO tree, List<BasMallCatalogDTO> list) {
list.stream()
.filter(node -> node.getParentId().equals(tree.getId()))
.map(node -> findChildren(node, list))
.forEachOrdered(children -> tree.getChildren().add(children));
return tree;
}
2024-8-5 16:59:23 枚举转树举例, 两种方法
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author chenyc51748
*/
public class CategoryUtil {
/**
* 定义枚举类型
*/
public enum CategoryEnum {
/**
* 关联主体分类
*/
/**
* 监管机构分类 type:regulatory_agencies
* 这里一级分类的parentCode为空用main中listToTree 如果固定为0 用listToTreeTemp
*/
XXX(null, "XXX", "金融监管", null, "regulatory_agencies"),
YYY(44, "YYY", "国家外汇管理局", "XXX", "regulatory_agencies"),
ZZZ(45, "ZZZ", "监管", "YYY", "regulatory_agencies"),
;
// 其他分类...
/**
* 数据库中分类数值 (不唯一 关联主体、监管机构...之间的是有相同的 父级分类id是null )
*/
private final Integer id;
/**
* 分类编码 唯一值 用来做转树结构
*/
private final String code;
/**
* 分类名称
*/
private final String name;
/**
* 父类编码
*/
private final String parentCode;
/**
* 分类类型
*/
private final String type;
CategoryEnum(Integer id, String code, String name, String parentCode, String type) {
this.id = id;
this.code = code;
this.name = name;
this.parentCode = parentCode;
this.type = type;
}
public Integer getId() {
return id;
}
public String getCode() {
return code;
}
public String getName() {
return name;
}
public String getParentCode() {
return parentCode;
}
public String getType() {
return type;
}
}
public static class Category {
private Integer id;
private String code;
private String name;
// 父分类代码,可能为 null
private String parentCode;
private String type;
// 子类集合
private List<Category> subCategories;
public Category(Integer id, String code, String name, String parentCode, String type) {
this.id = id;
this.code = code;
this.name = name;
this.parentCode = parentCode;
this.type = type;
this.subCategories = new ArrayList<>();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getParentCode() {
return parentCode;
}
public void setParentCode(String parentCode) {
this.parentCode = parentCode;
}
public List<Category> getSubCategories() {
return subCategories;
}
public void setSubCategories(List<Category> subCategories) {
this.subCategories = subCategories;
}
public void addSubCategory(Category subCategory) {
this.subCategories.add(subCategory);
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "Category{" +
"id=" + id +
", code='" + code + '\'' +
", name='" + name + '\'' +
", parentCode='" + parentCode + '\'' +
", type='" + type + '\'' +
", subCategories=" + subCategories +
'}';
}
}
/**
* 将枚举列表转换为 Category 列表
*/
private static List<Category> enumToList() {
return Arrays.stream(CategoryEnum.values())
.map(e -> new Category(e.getId(), e.getCode(), e.getName(), e.getParentCode(), e.getType()))
.collect(Collectors.toList());
}
/**
* 构建分类树并根据类型返回所有一级分类的列表
*/
public static List<Category> listToTree(String type) {
List<Category> allCategories = enumToList();
Map<String, Category> categoryMap = allCategories.stream()
.filter(category -> (type == null || type.isEmpty()) || category.getType().equals(type))
.collect(Collectors.toMap(Category::getCode, Function.identity()));
List<Category> rootCategories = new ArrayList<>();
for (Category category : categoryMap.values()) {
if (category.getParentCode() == null || "0".equals(category.getParentCode())) {
rootCategories.add(category);
} else {
Category parent = categoryMap.get(category.getParentCode());
if (parent != null) {
parent.addSubCategory(category);
}
}
}
// 递归地构建子分类树
buildSubCategoriesTree(rootCategories, categoryMap);
return rootCategories;
}
// 递归调用
private static void buildSubCategoriesTree(List<Category> categories, Map<String, Category> categoryMap) {
for (Category category : categories) {
List<Category> children = categoryMap.values().stream()
.filter(child -> child.getParentCode() != null && child.getParentCode().equals(category.getCode()))
.collect(Collectors.toList());
category.setSubCategories(children);
if (!children.isEmpty()) {
buildSubCategoriesTree(children, categoryMap);
}
}
}
/**
* 更新 getCategoryByCode 方法以接受 type 参数并进行筛选
*/
public static List<Category> getCategoryByCode(String code, String type) {
// 使用 type 参数筛选
List<Category> allCategories = listToTree(type);
List<Category> res = Lists.newArrayList();
Category temp = allCategories.stream()
.filter(category -> category.getCode().equals(code))
.findFirst()
.orElse(null);
if (ObjectUtil.isNotEmpty(temp)) {
res.add(temp);
}
return res;
}
// 主方法,用于验证
public static void main(String[] args) {
// 获取所有一级分类及其子分类的树形结构列表
// 第一种方法
List<Category> categories = listToTree("XXX");
List<Category> allCategories = listToTree(null);
// 根据指定code拿数据
// List<Category> res = getCategoryByCode(specificCode, type);
System.out.println(res);
// 第二种方法
List<Category> categories1 = enumToList();
List<Category> collect = listToTreeTemp(categories1);
System.out.println(collect);
}
public static List<Category> listToTreeTemp(List<Category> list) {
list.forEach(item->{
if(StringUtils.isBlank(item.getParentCode())){
item.setParentCode("0");
}
});
Set<String> parentIds = list.stream().map(Category::getParentCode).collect(Collectors.toSet());
Set<String> ids = list.stream().map(Category::getCode).collect(Collectors.toSet());
parentIds.removeAll(ids);
// 我这里可以直接用这个
// Set<String> parentIds = list.stream().filter(item->item.getParentCode().equals("0")).map(Category::getParentCode).collect(Collectors.toSet());
//递归查找子结点
return list.stream()
.filter(tree -> parentIds.contains(tree.getParentCode()))
.map(tree -> findChildren(tree, list))
.collect(Collectors.toList());
}
public static Category findChildren(Category tree, List<Category> list) {
list.stream()
.filter(node -> node.getParentCode().equals(tree.getCode()))
.map(node -> findChildren(node, list))
.forEachOrdered(children -> tree.getSubCategories().add(children));
return tree;
}
}
2025-3-5 13:50:32
需求:只填充指定id的树结构
// list为所有部门数据 现在没有树形结构
public List<Dept> listToTree(List<Dept> list, List<Long> targetIds) {
// 将所有部门按 id 分组
Map<Long, Dept> deptMap = list.stream()
.collect(Collectors.toMap(Dept::getId, dept -> dept));
// 构建子节点缓存
Map<Long, List<Dept>> childrenCache = new HashMap<>();
for (Dept dept : list) {
if (!childrenCache.containsKey(dept.getParentId())) {
childrenCache.put(dept.getParentId(), new ArrayList<>());
}
childrenCache.get(dept.getParentId()).add(dept);
}
// 获取所有目标 id 的子节点
List<Dept> result = new ArrayList<>();
for (Long id : targetIds) {
if (deptMap.containsKey(id)) {
result.add(buildTree(deptMap.get(id), childrenCache));
}
}
return result;
}
private Dept buildTree(Dept tree, Map<Long, List<Dept>> childrenCache) {
// 获取当前节点的子节点
List<Dept> children = childrenCache.getOrDefault(tree.getId(), new ArrayList<>());
children.forEach(child -> buildTree(child, childrenCache));
tree.setChildren(children);
return tree;
}