查詢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
工程演示后的結果如圖所示:

 
 
 
方式二,內存計算
   方式一查詢數據庫效率較低,方式二一次查詢所有數據,任何用stream流來計算轉化為樹,建議采用

普通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://www.jianshu.com/p/fa20d4bd8ad4

鏈接:https://blog.csdn.net/qq_41991665/article/details/90484690

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM