.Net集合排序的一種高級(jí)玩法實(shí)例教程
前言
本文主要介紹了關(guān)于.Net集合排序的另一種高級(jí)玩法,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考學(xué)習(xí),下面話(huà)不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧
背景:
學(xué)生有名稱(chēng)、學(xué)號(hào),
班級(jí)有班級(jí)名稱(chēng)、班級(jí)序號(hào)
學(xué)校有學(xué)校名稱(chēng)、學(xué)校編號(hào)(序號(hào))
需求
現(xiàn)在需要對(duì)學(xué)生進(jìn)行排序
第一排序邏輯
- 按學(xué)校編號(hào)(序號(hào))排列
- 再按班級(jí)序號(hào)排列
- 再按學(xué)生學(xué)號(hào)排列
當(dāng)然,在我們錄入數(shù)據(jù)庫(kù)信息的時(shí)候,有的人可能比較懶,沒(méi)有錄入 學(xué)校的序號(hào), 班級(jí)的序號(hào),學(xué)生的學(xué)號(hào) ,怎么辦? 那么就Plan B !
第二排序邏輯
- 按學(xué)校名稱(chēng)排列
- 再按班級(jí)的名稱(chēng)排列
- 再按學(xué)生名稱(chēng)排列
我編寫(xiě)了學(xué)校、班級(jí)、學(xué)生的實(shí)體關(guān)系代碼如下:
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; } } }
以前寫(xiě)的簡(jiǎn)單排序,還可以用OrderBy解決,如果之前寫(xiě)過(guò)的一篇文章:
但是這里的排序就比較復(fù)雜了,用簡(jiǎn)單的OrderBy恐怕是解決不了了。
Sort
.Net中,對(duì)List集合,有一個(gè)Sort字方法,讓我們選中Sort方法,F(xiàn)12,看看Sort方法長(zhǎng)哪樣?
可以看到Sort方法一共有四個(gè)重載,我們挑最基礎(chǔ)的一個(gè),Sort() 0參數(shù)的這個(gè),懂了這個(gè),其他幾個(gè)應(yīng)該也會(huì)懂了,我們看看該方法的描述:
雖然我英語(yǔ)不太好,但是這基礎(chǔ)的英語(yǔ)還是能看懂,大致是說(shuō):
用默認(rèn)的比較器對(duì)該List進(jìn)行排序。
那么,這個(gè)Comparer(比較器)是什么呢?
IComparable接口
其實(shí),它是接口IComparable下的一個(gè)方法,也就是說(shuō)只有實(shí)現(xiàn)了ICoparable接口下的這個(gè)叫比較器的方法才能使用Sort進(jìn)行排序,我們F12進(jìn)入到IComparable來(lái)看看這個(gè)接口:
可以看到,該接口只有一個(gè)CompareTo方法,我用我蹩腳的英語(yǔ)大致看懂了這句話(huà)的意思是:
定義一個(gè)比較方法來(lái)對(duì)制定類(lèi)型進(jìn)行排序。
該方法返回類(lèi)型為Int類(lèi)型。通過(guò)查找查找相關(guān)資料,了解到其返回值與其含義如下:
值 |
含義 |
復(fù)數(shù) |
該實(shí)例比傳入的Other實(shí)例小。 |
0 |
該實(shí)例與傳入的Other實(shí)例相等。 |
正數(shù) |
該實(shí)例比傳入的Other實(shí)例大。 |
知道了這個(gè)原則,我們就可以給Student類(lèi)繼承并實(shí)現(xiàn)該方法了。
對(duì)文章開(kāi)頭的排序需求,我們重溫一下:
第一排序邏輯(Int?)
- 按學(xué)校編號(hào)(序號(hào))排列
- 再按班級(jí)序號(hào)排列
- 再按學(xué)生學(xué)號(hào)排列
當(dāng)序號(hào)為空時(shí),用第二種排序邏輯,
第二排序邏輯(String)
- 按學(xué)校名稱(chēng)排列
- 再按班級(jí)的名稱(chēng)排列
- 再按學(xué)生名稱(chēng)排列
其實(shí)無(wú)非就是對(duì)Student中涉及到的Int?和string兩種數(shù)據(jù)類(lèi)型進(jìn)行比較。
Int?類(lèi)型(Nullable)和string已經(jīng)實(shí)現(xiàn)了Compare方法,其中Nullable的如下:
但是為了能更深入地理解該方法的使用,我自己來(lái)寫(xiě)一個(gè)Int?類(lèi)型數(shù)據(jù)比較的方法,如下:
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; //否則兩個(gè)數(shù)相等 }
其中,為什么我認(rèn)為有值的比Null的還小返回-1呢? 因?yàn)槲蚁氚袾ull的往后排,把有值的往前排,其他流行的做法是認(rèn)為有值的是比Null大的,即返回1,大家可以結(jié)合自己的業(yè)務(wù)需求選擇。
寫(xiě)好了Int?類(lèi)型數(shù)據(jù)比較的方法,還有String類(lèi)型數(shù)據(jù)的比較,我就不自己造輪子去寫(xiě)了,用現(xiàn)成的String.CompareOrdinal()方法。
然后,我們開(kāi)始給Student實(shí)現(xiàn)ICompare接口的CompareTo方法,如下:
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; //如果兩個(gè)值的引用相同,那么直接返回相等。 if (ReferenceEquals(null, other)) return 1; //如果該實(shí)例是空的,但是傳入的實(shí)例不是空的,那么返回1 //比較學(xué)校的序號(hào) var compareResult = CompareInit(this.Class.School.Order, other.Class.School.Order); if (compareResult != 0) return compareResult; //比較班級(jí)的序號(hào) compareResult = CompareInit(this.Class.Order, other.Class.Order); if (compareResult != 0) return compareResult; //比較學(xué)生的學(xué)號(hào) compareResult = CompareInit(this.Order, other.Order); if (compareResult != 0) return compareResult; //如果以上還未區(qū)分出大小,比較學(xué)校的名稱(chēng) compareResult = String.CompareOrdinal(this.Class.School.Name, other.Class.School.Name); if (compareResult != 0) return compareResult; //比較班級(jí)的名稱(chēng) compareResult = String.CompareOrdinal(this.Class.Name, other.Class.Name); if (compareResult != 0) return compareResult; //比較學(xué)生的名稱(chēng) return String.CompareOrdinal(this.Name, other.Name); }
實(shí)現(xiàn)該方法后,就可以對(duì)List<Student> 使用Sort方法了,我們來(lái)試試看。
using System; using System.Collections.Generic; namespace Sort { class Program { static void Main(string[] args) { var students = InitData(); students.Sort(); //此處執(zhí)行了Sort方法 Console.WriteLine("Name-Order"); foreach (var student in students) { Console.WriteLine($"學(xué)校:{student.Class.School.Name}-{student.Class.School.Order}>>班級(jí):{student.Class.Name}-{student.Class.Order}>>學(xué)生:{student.Name}-{student.Order}"); } Console.ReadLine(); } static List<Student> InitData() //創(chuàng)建數(shù)據(jù) { 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 }; } } }
執(zhí)行效果如下:
可以看到,學(xué)校B雖然是以B開(kāi)頭,但是因?yàn)槠贠rder為0比1更靠前,所以以O(shè)rder為準(zhǔn),學(xué)校B排到了最前面。
好幾天沒(méi)寫(xiě)了,寫(xiě)博客對(duì)我我而言,意義無(wú)非在于加深印象同時(shí)把我所掌握的東西分享給大家,這個(gè)方法是今天同事教我的,可能對(duì)園子里大神來(lái)說(shuō)這比較基礎(chǔ),但是相信如果掌握這個(gè)方法,對(duì)以后也許中復(fù)雜排序會(huì)有比較有用,希望對(duì)大家也能有所幫助。
項(xiàng)目的GitHub地址:
https://github.com/liuzhenyulive/Sort (本地下載)
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
看到本質(zhì)而不是現(xiàn)象--解決ASP.NET CS0016的問(wèn)題
看到本質(zhì)而不是現(xiàn)象--解決ASP.NET CS0016的問(wèn)題...2007-01-01asp.net+sqlserver實(shí)現(xiàn)的簡(jiǎn)單高效的權(quán)限設(shè)計(jì)示例
大部分系統(tǒng)都有權(quán)限系統(tǒng)。一般來(lái)說(shuō),它能管控人員對(duì)某個(gè)否頁(yè)面的訪問(wèn);對(duì)某些字段、控件可見(jiàn)或者不可見(jiàn)。對(duì)gridview中的數(shù)據(jù)是否可刪除、可添加、可新增等等。2010-04-04Asp.Net 網(wǎng)站優(yōu)化系列之?dāng)?shù)據(jù)庫(kù)優(yōu)化 分字訣 分表(縱向拆分,橫向分區(qū))
上篇談了分庫(kù),這一篇我們來(lái)分表2010-06-06VB.net 查詢(xún)獲取數(shù)據(jù)庫(kù)數(shù)據(jù)信息
VB.net 查詢(xún)獲取數(shù)據(jù)庫(kù)數(shù)據(jù)信息實(shí)現(xiàn)函數(shù),需要的朋友可以參考下,代碼比較簡(jiǎn)單。2009-07-07ASP.NET MVC實(shí)現(xiàn)批量文件上傳
這篇文章主要為大家詳細(xì)介紹了ASP.NET MVC實(shí)現(xiàn)批量文件上傳,簡(jiǎn)單介紹單文件上傳的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09Asp.net管理信息系統(tǒng)中數(shù)據(jù)統(tǒng)計(jì)功能的實(shí)現(xiàn)方法
這篇文章主要介紹了Asp.net管理信息系統(tǒng)中數(shù)據(jù)統(tǒng)計(jì)功能的實(shí)現(xiàn)方法,需要的朋友可以參考下2017-07-07Asp.net treeview實(shí)現(xiàn)無(wú)限級(jí)樹(shù)實(shí)現(xiàn)代碼
最近研究了一下treeview,發(fā)現(xiàn)有兩種實(shí)現(xiàn)無(wú)限級(jí)樹(shù)的方法,文字不想多寫(xiě),直入主題。2009-09-09