将List对象列表转为树形结构

[复制链接]
发表于 5 天前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
Java 中将平铺 List 转换为树形结构

在社交标签、菜单、分类等场景中,数据库通常以平铺的父子关系表存储数据(每条记录带一个 parentId)。前端渲染时往往需要树形结构。本文给出一个基于 Java 的实体定义与“List 转 Tree”实现示例。

一、实体类 SocialTag

标签实体继承基础实体,关键字段包括主键 id、标签名称 tagName、父级 id parentId、标签等级 levelNo、排序号 sortNo、可用状态 enableFlag、删除标识 deleteFlag,并额外维护一个非表字段 childSocialTagList 存放子节点:

  1. package com.nijia.vip.social.entity;

  2. import java.util.ArrayList;
  3. import java.util.List;

  4. import com.baomidou.mybatisplus.annotation.IdType;
  5. import com.baomidou.mybatisplus.annotation.TableField;
  6. import com.baomidou.mybatisplus.annotation.TableId;
  7. import com.nijia.base.entity.BaseEntity;

  8. import io.swagger.annotations.ApiModelProperty;
  9. import lombok.Data;

  10. /**
  11. * 社交--个人标签(SocialTag)表实体类
  12. *
  13. * @author whp
  14. * @since 2022-06-23 14:15:53
  15. */
  16. @SuppressWarnings("serial")
  17. @Data
  18. public class SocialTag extends BaseEntity {
  19.     private static final long serialVersionUID = 1L;

  20.     @TableId(value = "id", type = IdType.ASSIGN_ID)
  21.     @ApiModelProperty("主键")
  22.     private Long id;

  23.     @ApiModelProperty("标签名称")
  24.     private String tagName;

  25.     @ApiModelProperty("父级id")
  26.     private Long parentId;

  27.     @ApiModelProperty("标签等级【1-1级,2-2级】")
  28.     private Integer levelNo;

  29.     @ApiModelProperty("排序号")
  30.     private Integer sortNo;

  31.     @ApiModelProperty("可用状态【1-可用,0-不可用】")
  32.     private Integer enableFlag;

  33.     @ApiModelProperty("删除标识【1-删除,0-正常】")
  34.     private Integer deleteFlag;

  35.     @TableField(exist = false)
  36.     private List<SocialTag> childSocialTagList = new ArrayList<SocialTag>();
  37. }
复制代码


二、List 转 Tree 的核心算法

思路是先把 List 转成以 id 为键的 Map,再遍历每个节点:若其 parentId 对应的父节点不存在,说明它是顶级节点,加入结果集;否则把它挂到父节点的 childSocialTagList 中。

  1. private static List<SocialTag> convertListToTree(List<SocialTag> socialTagList) {
  2.     List<SocialTag> resultList = new ArrayList<SocialTag>();
  3.     if (CollectionUtils.isEmpty(socialTagList)) {
  4.         return resultList;
  5.     }

  6.     // List 转为 Map(id -> 节点)
  7.     Map<Long, SocialTag> socialTagMap =
  8.             socialTagList.stream().collect(Collectors.toMap(SocialTag::getId, item -> item));

  9.     for (SocialTag socialTag : socialTagList) {
  10.         SocialTag parentSocialTag = socialTagMap.get(socialTag.getParentId());
  11.         // 该节点为空,说明是顶级节点
  12.         if (parentSocialTag == null) {
  13.             resultList.add(socialTag);
  14.             continue;
  15.         }
  16.         // 把自己加到父节点对象里
  17.         parentSocialTag.getChildSocialTagList().add(socialTag);
  18.     }
  19.     return resultList;
  20. }
复制代码


三、构造测试数据并验证

通过 initData() 准备两级标签(如 Java/Springboot、DB/Mysql 等),调用转换后打印 JSON:

  1. public static void main(String[] args) {
  2.     List<SocialTag> resultList = convertListToTree(initData());
  3.     System.out.println(JavaJsonConvert.javaToJson(resultList));
  4. }
复制代码


其中 initData() 创建若干 SocialTag,设置 id、parentId、levelNo 与创建时间后返回列表。运行后即可得到嵌套了 childSocialTagList 的树形结果。

小结

该实现时间复杂度为 O(n),借助 Map 一次遍历即可完成挂载,比嵌套循环查找父节点更高效,适合标签、菜单等一对多层级数据的后端组装。

qidao123.com企服评测-应用市场 编辑提示
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表