查询list转化为tree的两种方式及排序
方式一,数据库查询tree;
MyBatis collection 集合
MyBatis 是数据持久层框架,支持定制化 SQL、存储过程以及高级映射。尤其强大在于它的映射语句,比如高级映射中的 collection 集合。
collection 集合,集合常用的两个场景是集合的嵌套查询、集合的嵌套结果。集合的嵌套结果就是查询结果对应嵌套子对象。这里就是利用 collection 集合嵌套查询树形节点。下面来一一实现。
查询树形节点 Web 案例
创建数据库表
节点表:
CREATE TABLE `node` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`parent_id` int(11) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `parent_id` (`parent_id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COMMENT='节点表'
简单的节点父子关系设计,下面插入几条数据:
INSERT INTO node (name, parent_id) VALUES ('一级节点A', 0);
INSERT INTO node (name, parent_id) VALUES ('一级节点B', 0);
INSERT INTO node (name, parent_id) VALUES ('一级节点C', 0);
INSERT INTO node (name, parent_id) VALUES ('二级节点AA', 1);
INSERT INTO node (name, parent_id) VALUES ('二级节点aa', 1);
INSERT INTO node (name, parent_id) VALUES ('二级节点BB', 2);
INSERT INTO node (name, parent_id) VALUES ('三级级节点AAA', 4);
INSERT INTO node (name, parent_id) VALUES ('三级级节点aaa', 4);
INSERT INTO node (name, parent_id) VALUES ('三级级节点BBB', 6);
重要的还是看 collection 在 xml 的映射实现,NodeMapper.xml 代码如下:
<mapper namespace="org.mybatis.dao.NodeDao">
<resultMap id="BaseTreeResultMap" type="org.mybatis.domain.Node">
<result column="id" property="id"/>
<result column="name" property="name"/>
<collection column="id" property="next" javaType="java.util.ArrayList"
ofType="org.mybatis.domain.Node" select="getNextNodeTree"/>
</resultMap>
<resultMap id="NextTreeResultMap" type="org.mybatis.domain.Node">
<result column="id" property="id"/>
<result column="name" property="name"/>
<collection column="id" property="next" javaType="java.util.ArrayList"
ofType="org.mybatis.domain.Node" select="getNextNodeTree"/>
</resultMap>
<sql id="Base_Column_List">
id, name
</sql>
<select id="getNextNodeTree" resultMap="NextTreeResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM node
WHERE parent_id = #{id}
</select>
<select id="getNodeTree" resultMap="BaseTreeResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM node
WHERE parent_id = 0
</select>
</mapper>
在 dao 层,我们只调用 getNodeTree 方法,parent_id = 0 代表顶级节点。然后通过 collection 节点继续调用 getNextNodeTree 方法进行循环调用。
<collection column="id" property="next" javaType="java.util.ArrayList"
ofType="org.mybatis.domain.Node" select="getNextNodeTree"/>
以下是关键的知识点:
- column 代表会拿父节点 id ,作为参数获取 next 对象
- javaType 代表 next 对象是个列表,其实可以省略不写
- ofType 用来区分 JavaBean 属性类型和集合包含的类型
- select 是用来执行循环哪个 SQL
工程代码地址:https://github.com/JeffLi1993/myabtis-learning-example
工程演示后的结果如图所示:

普通list转树状list
public static List<User> list2tree(List<User> list) {
List<User> result = new ArrayList<>();
Map<Object, User> hash = list.stream().collect(Collectors.toMap(u -> u.getId(), u -> u));
for (User u : list) {
User p = hash.get(u.getParent());
if (p == null) {
result.add(u);
} else {
if (p.getChildren() == null) {
p.setChildren(new ArrayList<>());
}
p.getChildren().add(u);
}
}
return result;
}
树状list转普通list
public static List<User> tree2list(List<User> list) {
List<User> result = new ArrayList<>();
for (User u : list) {
List<User> c = u.getChildren();
result.add(u);
if (!CollectionUtils.isEmpty(c)) {
result.addAll(tree2list(c));
u.setChildren(null);//
}
}
return result;
}
java8 stream多字段排序
使用java8新特性,下面先来点基础的
|
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
32
33
|
List<类> list; 代表某集合//返回 对象集合以类属性一升序排序list.stream().sorted(Comparator.comparing(类::属性一));//返回 对象集合以类属性一降序排序 注意两种写法list.stream().sorted(Comparator.comparing(类::属性一).reversed());//先以属性一升序,结果进行属性一降序list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()));//以属性一降序//返回 对象集合以类属性一升序 属性二升序list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二));//返回 对象集合以类属性一降序 属性二升序 注意两种写法list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二));//先以属性一升序,升序结果进行属性一降序,再进行属性二升序list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二));//先以属性一降序,再进行属性二升序//返回 对象集合以类属性一降序 属性二降序 注意两种写法list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,升序结果进行属性一降序,再进行属性二降序list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一降序,再进行属性二降序//返回 对象集合以类属性一升序 属性二降序 注意两种写法list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二).reversed());//先以属性一升序,升序结果进行属性一降序,再进行属性二升序,结果进行属性一降序属性二降序list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,再进行属性二降序<br><br><br> |
通过以上例子我们可以发现
1. Comparator.comparing(类::属性一).reversed();
2. Comparator.comparing(类::属性一,Comparator.reverseOrder());
两种排序是完全不一样的,一定要区分开来 1 是得到排序结果后再排序,2是直接进行排序,很多人会混淆导致理解出错,2更好理解,建议使用2
3.注意排序后需要另外一个lis来接收List<xxx> list= Stream.sort(xxx).collect(toList());
class testRun {
public static void main(String[] args) {
List<test> testList = new ArrayList<>();
Date d = DateUtils.now();
for (int i = 1; i <= 3; i++) {
test t = new test(i, DateUtils.addDays(d, i));
testList.add(t);
}
for (int i = 1; i <= 3; i++) {
test t = new test(i, DateUtils.addMonths(d, i));
testList.add(t);
}
testList.forEach(o -> {
System.out.println(o.toString());
});
List<test> sort = testList.stream().sorted(Comparator.comparing(test::getState).thenComparing(test::getTime,Comparator.reverseOrder())).collect(toList());
System.out.println("------------------------------------");
sort.forEach(o -> {
System.out.println(o.toString());
});
}
}
参考
链接:https://blog.csdn.net/qq_41991665/article/details/90484690
查询list转化为tree的两种方式及排序的更多相关文章
- Java中将xml文件转化为json的两种方式
原文地址https://blog.csdn.net/a532672728/article/details/76312475 最近有个需求,要将xml转json之后存储在redis中,找来找去发现整体来 ...
- C#复杂XML反序列化为实体对象两种方式
前言 今天主要讲的是如何把通过接口获取到的Xml数据转换成(反序列化)我们想要的实体对象,当然Xml反序列化和Json反序列化的方式基本上都是大同小异.都是我们事先定义好对应的对应的Xml实体模型,不 ...
- easyui里面的加载tree的两种方式
第一种: 使用EasyUI中Tree 符合EasyUI中Tree的Json格式,我们先看一下,格式是如何的 [{ "id":1, "text":"My ...
- linq 实现查询字符串拼接 : And 和 OR 两种方式
N年前我们是这样来 拼接查询字符串的: // 何问起 hovertree.com public string Test(string a, string b, string c,string d) { ...
- java.util.Arrays.sort两种方式的排序(及文件读写练习)
import java.io.*; import java.util.*; public class SortTest{ public static void main(String args[]) ...
- hibernate级联查询映射的两种方式
Hibernate主要支持两种查询方式:HQL查询和Criteria查询.前者应用较为广发,后者也只是调用封装好的接口. 现在有一个问题,就是实现多表连接查询,且查询结果集不与任何一个实体类对应,怎么 ...
- SpringBoot集成Mybatis实现多表查询的两种方式(基于xml)
下面将在用户和账户进行一对一查询的基础上进行介绍SpringBoot集成Mybatis实现多表查询的基于xml的两种方式. 首先我们先创建两个数据库表,分别是user用户表和account账户表 ...
- MySQL关闭查询缓存(QC)的两种方法
MySQL Query Cache 会缓存select 查询,安装时默认是开启的,但是如果对表进行INSERT, UPDATE, DELETE, TRUNCATE, ALTER TABLE, DROP ...
- 五 Mybatis一对一关联查询的两种方式(基于resultType&基于resultMap)
关联查询: 一个用户对应多个订单,一个订单只有一个用户 订单关联用户:两种方式 一:基于resultTYpe,一个与表关系一样的pojo实现 主表订单,从表用户 首先要有一个与关联查询表关系一样的po ...
随机推荐
- Verilog求余
在实现三角函数时,考虑到函数的周期性,综量(自变量)需对周期做求余运算. 假设函数周期为T = 2^N,那么求余运算就是直接取该数的低N位,即: 以M位正数为例(符号位为0),reg [M-1:0] ...
- 51 Nod 1287 加农炮(单调队列思想+二分)
1287 加农炮 题目来源: Codility 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 收藏 关注 一个长度为M的正整数数组A,表示从左向右的地形高度 ...
- Noip2015 提高组 Day1
T1神奇的幻方 直通 思路: 制定一个lrow记录上一个数字所在的行数,lcolume记录上一个数字所在的列数,然后根据题目的描述进行更改即可 上代码: #include <iostream&g ...
- 二维DFT
学习DIP第4天 傅里叶变换数学原理会在后续完整介绍,目前只实现代码,观察下结果,公式在上一篇博客中已经描述 内容迁移至 http://www.face2ai.com/DIP-2-2-二维DFT/ h ...
- Django基础之form表单
1. form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时, 我们在好多场景下都需要对用户的输入做校验, 比如 ...
- Java线程之join
简述 Thread类的join方法用来使main线程进入阻塞状态,进而等待调用join方法的线程执行,join有三个重载方法: public final void join() 使主线程进入阻塞状态, ...
- 【洛谷4001】 [ICPC-Beijing 2006]狼抓兔子(最小割)
传送门 洛谷 Solution 直接跑最小割板子就好了. 代码实现 #include<stdio.h> #include<stdlib.h> #include<strin ...
- NSPredicate谓词的用法
在IOS开发Cocoa框架中提供了一个功能强大的类NSPredicate,下面来讨论一下它的强大之处在哪...NSPredicate继承自NSObject,它有两个派生的子类• NSCompariso ...
- Flutter移动电商实战 --(1)项目学习记录
1.项目相关截图 2.项目知识点梳理图 Dio2.0: Dio是一个强大的 Dart Http 请求库,支持 Restful API.FormData.拦截器.请求取消等操作. Swiper: Swi ...
- ansiblle---roles
使用ansible中的roles来管理主机. 剧本中的roles你现在已经学过 tasks 和 handlers,那怎样组织 playbook 才是最好的方式呢?简单的回答就是:使用 roles ! ...