前言
本文主要介紹了關于.Net集合排序的另一種高級玩法,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考學習,下面話不多說了,來一起看看詳細的介紹吧
背景:
學生有名稱、學號,
班級有班級名稱、班級序號
學校有學校名稱、學校編號(序號)
需求
現在需要對學生進行排序
第一排序邏輯
- 按學校編號(序號)排列
- 再按班級序號排列
- 再按學生學號排列
當然,在我們錄入數據庫信息的時候,有的人可能比較懶,沒有錄入 學校的序號, 班級的序號,學生的學號 ,怎么辦? 那么就Plan B !
第二排序邏輯
- 按學校名稱排列
- 再按班級的名稱排列
- 再按學生名稱排列
我編寫了學校、班級、學生的實體關系代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
namespace Sort { public class School { public int ? Order { get ; set ; } public string Name { get ; set ; } } public class Class { public int ? Order { get ; set ; } public string Name { get ; set ; } public School School { get ; set ; } } public class Student { public int ? Order { get ; set ; } public string Name { get ; set ; } public Class Class { get ; set ; } } } |
以前寫的簡單排序,還可以用OrderBy解決,如果之前寫過的一篇文章:
《.Net中集合排序還可以這么玩》
但是這里的排序就比較復雜了,用簡單的OrderBy恐怕是解決不了了。
Sort
.Net中,對List集合,有一個Sort字方法,讓我們選中Sort方法,F12,看看Sort方法長哪樣?
可以看到Sort方法一共有四個重載,我們挑最基礎的一個,Sort() 0參數的這個,懂了這個,其他幾個應該也會懂了,我們看看該方法的描述:
雖然我英語不太好,但是這基礎的英語還是能看懂,大致是說:
用默認的比較器對該List進行排序。
那么,這個Comparer(比較器)是什么呢?
IComparable接口
其實,它是接口IComparable下的一個方法,也就是說只有實現了ICoparable接口下的這個叫比較器的方法才能使用Sort進行排序,我們F12進入到IComparable來看看這個接口:
可以看到,該接口只有一個CompareTo方法,我用我蹩腳的英語大致看懂了這句話的意思是:
定義一個比較方法來對制定類型進行排序。
該方法返回類型為Int類型。通過查找查找相關資料,了解到其返回值與其含義如下:
值 |
含義 |
復數 |
該實例比傳入的Other實例小。 |
0 |
該實例與傳入的Other實例相等。 |
正數 |
該實例比傳入的Other實例大。 |
知道了這個原則,我們就可以給Student類繼承并實現該方法了。
對文章開頭的排序需求,我們重溫一下:
第一排序邏輯(Int?)
- 按學校編號(序號)排列
- 再按班級序號排列
- 再按學生學號排列
當序號為空時,用第二種排序邏輯,
第二排序邏輯(String)
- 按學校名稱排列
- 再按班級的名稱排列
- 再按學生名稱排列
其實無非就是對Student中涉及到的Int?和string兩種數據類型進行比較。
Int?類型(Nullable)和string已經實現了Compare方法,其中Nullable的如下:
但是為了能更深入地理解該方法的使用,我自己來寫一個Int?類型數據比較的方法,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
private int CompareInit( int ? x, int ? y) { if (x == null && y == null ) //如果都是空 那么返回0相等 return 0; if (x.HasValue && y == null ) //如果傳入X有值,但是Y是空的,那么X比Y小 返回-1。 return -1; if (x == null && y.HasValue) //如果傳入X為空,但是Y有值,那么X比Y大 返回1。 return 1; if (x.Value > y.Value) return 1; if (x.Value < y.Value) return -1; return 0; //否則兩個數相等 } |
其中,為什么我認為有值的比Null的還小返回-1呢? 因為我想把Null的往后排,把有值的往前排,其他流行的做法是認為有值的是比Null大的,即返回1,大家可以結合自己的業務需求選擇。
寫好了Int?類型數據比較的方法,還有String類型數據的比較,我就不自己造輪子去寫了,用現成的String.CompareOrdinal()方法。
然后,我們開始給Student實現ICompare接口的CompareTo方法,如下:
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
|
public class Student : IComparable<Student> { public int ? Order { get ; set ; } public string Name { get ; set ; } public Class Class { get ; set ; } public int CompareTo(Student other) { if (ReferenceEquals( this , other)) return 0; //如果兩個值的引用相同,那么直接返回相等。 if (ReferenceEquals( null , other)) return 1; //如果該實例是空的,但是傳入的實例不是空的,那么返回1 //比較學校的序號 var compareResult = CompareInit( this .Class.School.Order, other.Class.School.Order); if (compareResult != 0) return compareResult; //比較班級的序號 compareResult = CompareInit( this .Class.Order, other.Class.Order); if (compareResult != 0) return compareResult; //比較學生的學號 compareResult = CompareInit( this .Order, other.Order); if (compareResult != 0) return compareResult; //如果以上還未區分出大小,比較學校的名稱 compareResult = String.CompareOrdinal( this .Class.School.Name, other.Class.School.Name); if (compareResult != 0) return compareResult; //比較班級的名稱 compareResult = String.CompareOrdinal( this .Class.Name, other.Class.Name); if (compareResult != 0) return compareResult; //比較學生的名稱 return String.CompareOrdinal( this .Name, other.Name); } |
實現該方法后,就可以對List<Student> 使用Sort方法了,我們來試試看。
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
using System; using System.Collections.Generic; namespace Sort { class Program { static void Main( string [] args) { var students = InitData(); students.Sort(); //此處執行了Sort方法 Console.WriteLine( "Name-Order" ); foreach (var student in students) { Console.WriteLine($ "學校:{student.Class.School.Name}-{student.Class.School.Order}>>班級:{student.Class.Name}-{student.Class.Order}>>學生:{student.Name}-{student.Order}" ); } Console.ReadLine(); } static List<Student> InitData() //創建數據 { var school1 = new School() { Order = 1, Name = "A" , }; var school2 = new School { Name = "B" , Order = 0 }; var class1 = new Class { Order = 1, Name = "1" , School = school1, }; var class2 = new Class { Order = 2, Name = "2" , School = school1, }; var class3 = new Class { Order = 1, Name = "1" , School = school2, }; var student1 = new Student { Order = 1, Name = "1" , Class = class1, }; var student2 = new Student { Order = 2, Name = "2" , Class = class1, }; var student3 = new Student { Order = 3, Name = "3" , Class = class1, }; var student4 = new Student { Order = 1, Name = "1" , Class = class2, }; var student5 = new Student { Order = 1, Name = "1" , Class = class3, }; return new List<Student> { student5, student3, student4, student2, student1 }; } } } |
執行效果如下:
可以看到,學校B雖然是以B開頭,但是因為期Order為0比1更靠前,所以以Order為準,學校B排到了最前面。
好幾天沒寫了,寫博客對我我而言,意義無非在于加深印象同時把我所掌握的東西分享給大家,這個方法是今天同事教我的,可能對園子里大神來說這比較基礎,但是相信如果掌握這個方法,對以后也許中復雜排序會有比較有用,希望對大家也能有所幫助。
項目的GitHub地址:
https://github.com/liuzhenyulive/Sort
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:https://www.cnblogs.com/CoderAyu/p/9058024.html