C#?List.Sort排序(默認(rèn)排序和自定義排序)
C#中,List.Sort() 不僅為我們提供了默認(rèn)的排序方法,還為我們提供了4種自定義排序的方法,通過(guò)默認(rèn)排序方法,我們無(wú)需重寫(xiě)任何Sort()方法的實(shí)現(xiàn)代碼,就能對(duì)單參數(shù)類型的List數(shù)據(jù)進(jìn)行單一規(guī)則的排序,如果通過(guò)對(duì)這些方法進(jìn)行改進(jìn)我們可以輕松做到對(duì)多參數(shù)、多規(guī)則的復(fù)雜排序。
C# 默認(rèn)排序方法Sort、Reverse
排序Sort,倒序Reverse
//默認(rèn)是元素第一個(gè)字母按升序 list.Sort(); //將List里面元素順序反轉(zhuǎn) list.Reverse(); //從第二個(gè)元素開(kāi)始,反轉(zhuǎn)4個(gè)元素 //結(jié)果list里最后的順序變成"Ha", "Jay", "Lily", "Tom", "Hunter", "Jim", "Kuku", "Locu" list.Reverse(1,4);
C#自定義排序的4種方法
List<T>.Sort(); List<T>.Sort(IComparer<T> Comparer); List<T>.Sort(int index, int count, IComparer<T> Comparer); List<T>.Sort(Comparison<T> comparison);
實(shí)現(xiàn)目標(biāo)
假設(shè)存在一個(gè)People類,包含Name、Age屬性,在客戶端中創(chuàng)建List保存多個(gè)實(shí)例,希望對(duì)List中的內(nèi)容根據(jù)Name和Age參數(shù)進(jìn)行排序,排序規(guī)則為,先按姓名升序排序,如果姓名相同再按年齡的升序排序:
class People { public People(string name, int age) { Name = name; Age = age; } public string Name { get; set; } //姓名 public int Age { get; set; } //年齡 } // 客戶端 class Client { static void Main(string[] args) { List<People> peopleList = new List<People>(); peopleList.Add(new People("張三", 22)); peopleList.Add(new People("張三", 24)); peopleList.Add(new People("李四", 18)); peopleList.Add(new People("王五", 16)); peopleList.Add(new People("王五", 30)); } }
方法一、繼承IComparable接口,實(shí)現(xiàn)CompareTo()方法
對(duì)People類繼承IComparable接口,實(shí)現(xiàn)CompareTo()方法
該方法為系統(tǒng)默認(rèn)的方法,單一參數(shù)時(shí)會(huì)默認(rèn)進(jìn)行升序排序。但遇到多參數(shù)(Name、Age)排序時(shí),我們需要對(duì)該默認(rèn)方法進(jìn)行修改。
方法一:People類繼承IComparable接口,實(shí)現(xiàn)CompareTo()方法
IComparable<T>:定義由值類型或類實(shí)現(xiàn)的通用比較方法,旨在創(chuàng)建特定于類型的比較方法以對(duì)實(shí)例進(jìn)行排序。
原理:自行實(shí)現(xiàn)的CompareTo()方法會(huì)在list.Sort()內(nèi)部進(jìn)行元素兩兩比較,最終實(shí)現(xiàn)排序
class People : IComparable<People> { public People(string name, int age) { Name = name;Age = age; } public string Name { get; set; } public int Age { get; set; } // list.Sort()時(shí)會(huì)根據(jù)該CompareTo()進(jìn)行自定義比較 public int CompareTo(People other) { if (this.Name != other.Name) { return this.Name.CompareTo(other.Name); } else if (this.Age != other.Age) { return this.Age.CompareTo(other.Age); } else return 0; } } // 客戶端 peopleList.Sort(); // OUTPUT: // 李四 18 // 王五 16 // 王五 30 // 張三 22 // 張三 24
方法二:增加外部比較類,繼承IComparer接口、實(shí)現(xiàn)Compare()方法
增加People類的外部比較類,繼承IComparer接口、實(shí)現(xiàn)Compare()方法
區(qū)別于上述繼承IComparable的方法,該方法不可在People內(nèi)繼承實(shí)現(xiàn)IComparer接口,而是需要新建比較方法類進(jìn)行接口實(shí)現(xiàn)
方法二:新建PeopleComparer類、繼承IComparer接口、實(shí)現(xiàn)Compare()方法
原理:list.Sort()將PeopleComparer類的實(shí)例作為參數(shù),在內(nèi)部使用Compare()方法進(jìn)行兩兩比較,最終實(shí)現(xiàn)排序(注:上述方法為CompareTo(),此處為Compare()方法)
// 自定義比較方法類 class PeopleComparer : IComparer<People> { // 區(qū)別于CompareTo()單參數(shù),此處為雙參數(shù) public int Compare(People x, People y) { if (x.Name != y.Name) { return x.Name.CompareTo(y.Name); } else if (x.Age != y.Age) { return x.Age.CompareTo(y.Age); } else return 0; } } // 客戶端 // 傳入?yún)?shù)為自定義比較類的實(shí)例 peopleList.Sort(new PeopleComparer()); // OUTPUT: // 李四 18 // 王五 16 // 王五 30 // 張三 22 // 張三 24
同理,List<T>.Sort(int index, int count, IComparer<T> Comparer) 方法的參數(shù):待排元素起始索引、待排元素個(gè)數(shù)、排序方法
方法三、采用泛型委托 Comparison<T>,綁定自定義的比較方法
區(qū)別于上述繼承接口的方法,此方法的參數(shù)為 泛型委托 Comparison<T>
委托原型:public delegate int Comparison<in T>(T x, T y);
方法三:依照委托的使用方法,首先創(chuàng)建委托實(shí)例MyComparison,并綁定到自定義的比較方法PeopleComparison()上,最終調(diào)用list.Sort()時(shí) 將委托實(shí)例傳入
原理:list.Sort()根據(jù)傳入的委托方法,進(jìn)行兩兩元素比較最終實(shí)現(xiàn)排序
// 客戶端 class Client { // 方法0 自定義比較方法 public static int PeopleComparison(People p1, People p2) { if (p1.Name != p2.Name) { return p1.Name.CompareTo(p2.Name); } else if (p1.Age != p2.Age) { return p1.Age.CompareTo(p2.Age); } else return 0; } static void Main(string[] args) { / 創(chuàng)建list ... / // 方法0 創(chuàng)建委托實(shí)例并綁定 Comparison<People> MyComparison = PeopleComparison; // 傳入該實(shí)例實(shí)現(xiàn)比較方法 peopleList.Sort(MyComparison); // OUTPUT: // 李四 18 // 王五 16 // 王五 30 // 張三 22 // 張三 24 } }
泛型委托用Lambda表達(dá)式
此外,既然Comparison<T>
是泛型委托,則完全可以用 Lambda表達(dá)式 進(jìn)行描述:
// Lambda表達(dá)式實(shí)現(xiàn)Comparison委托 peopleList.Sort((p1, p2) => { if (p1.Name != p2.Name) { return p2.Name.CompareTo(p1.Name); } else if (p1.Age != p2.Age) { return p2.Age.CompareTo(p1.Age); } else return 0; }); // OUTPUT: // 張三 24 // 張三 22 // 王五 30 // 王五 16 // 李四 18
總結(jié)
雖然本文僅使用了List<T>一種容器對(duì)Sort()方法進(jìn)行闡述,但是不同容器的使用Sort()的方法大相徑庭,因?yàn)楹诵牡脑矶际菓?yīng)用兩種接口及泛型委托:
兩種接口:IComparable<T> 、 IComparer<T>
泛型委托:Comparison<T>
參考
IComparable接口 - Microsoft IComparable
Comparison委托 - Microsoft Comparison
IComparer接口 - Microsoft IComparer 接口 (System.Collections) | Microsoft Docs
IComparable和IComparer接口和自定義比較器 - My_Pure C# IComparable和IComparer接口和自定義比較器
附:一個(gè)完整的測(cè)試Demo
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ListSort { class Program { static void DisplayInfo<T>(List<T> list) { //輸出List元素內(nèi)容 foreach(var item in list) { System.Console.Write("{0} ",item.ToString()); } System.Console.WriteLine(""); } // 方法3 自定義委托泛型比較方法 public static int PeopleComparison(People p1, People p2) { if (p1.Name != p2.Name) { return p1.Name.CompareTo(p2.Name); } else if (p1.Age != p2.Age) { return p1.Age.CompareTo(p2.Age); } else return 0; } static void Main(string[] args) { List<People> peopleList = new List<People>(); peopleList.Add(new People("張三", 22)); peopleList.Add(new People("張三", 24)); peopleList.Add(new People("李四", 18)); peopleList.Add(new People("王五", 16)); peopleList.Add(new People("王五", 30)); System.Console.WriteLine("排序前原始數(shù)據(jù):"); DisplayInfo(peopleList); System.Console.WriteLine("------------------------------------"); System.Console.WriteLine("方法1排序后數(shù)據(jù):"); peopleList.Sort(); DisplayInfo(peopleList); System.Console.WriteLine("方法2排序后數(shù)據(jù):"); DisplayInfo(peopleList); // 方法1 使用IComparer<T>接口。 peopleList.Sort(new PeopleComparer()); // 方法2 除以上兩種方法以外還可以使用另一種方法,在People類中實(shí)現(xiàn)IComparable<T> peopleList.Sort(); System.Console.WriteLine("方法3排序后數(shù)據(jù):"); DisplayInfo(peopleList); // 方法3 創(chuàng)建泛型委托實(shí)例并綁定 Comparison<People> MyComparison = PeopleComparison; // 傳入該實(shí)例實(shí)現(xiàn)比較方法 peopleList.Sort(MyComparison); System.Console.WriteLine("方法3排序后數(shù)據(jù):"); DisplayInfo(peopleList); // 方法3 使用Comparison<T>委托,Lambda寫(xiě)法 peopleList.Sort((left, right) => { //先按姓名排序,如果姓名相同再按年齡排序 int x = left.Name.CompareTo(right.Name); if(x==0) { if (left.Age > right.Age) x = 1; else if (left.Age == right.Age) x = 0; else x = -1; } return x; }); } } //方法一 public class People : IComparable<People> { public int Age { get;set;} public string Name { get;set;} public People(string name,int age) { this.Name = name; this.Age = age; } public override string ToString() { string result = ""; result = "["+this.Name+","+ this.Age.ToString()+"]"; return result; } public int CompareTo(People other) { int x = this.Name.CompareTo(other.Name); if(x==0) { if (this.Age > other.Age) x = 1; else if (this.Age == other.Age) x = 0; else x = -1; } return x; } } //方法二 public class PeopleComparer : IComparer<People> { public int Compare(People left, People right) { int x = left.Name.CompareTo(right.Name); if(x==0) { if (left.Age > right.Age) x = 1; else if (left.Age == right.Age) x = 0; else x = -1; } return x; } } }
到此這篇關(guān)于C# List.Sort排序(默認(rèn)排序和自定義排序)的文章就介紹到這了,更多相關(guān)C# List.Sort排序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#中數(shù)組、ArrayList、List、Dictionary的用法與區(qū)別淺析(存取數(shù)據(jù))
在工作中經(jīng)常遇到C#數(shù)組、ArrayList、List、Dictionary存取數(shù)據(jù),但是該選擇哪種類型進(jìn)行存儲(chǔ)數(shù)據(jù)呢?很迷茫,今天小編抽空給大家整理下這方面的內(nèi)容,需要的朋友參考下吧2017-02-02Unity Shader實(shí)現(xiàn)紋理遮罩效果
這篇文章主要為大家詳細(xì)介紹了Unity Shader實(shí)現(xiàn)紋理遮罩效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04C#實(shí)現(xiàn)滑動(dòng)開(kāi)關(guān)效果
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)滑動(dòng)開(kāi)關(guān)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07json格式數(shù)據(jù)分析工具PageElement類分享(仿Session寫(xiě)法)
json格式數(shù)據(jù)分析工具PageElement類分享,可像Session一樣自由獲取Json元素的Key與Value。并可方便與ADO進(jìn)行交互2013-12-12Unity3D Shader實(shí)現(xiàn)鏡子效果
這篇文章主要為大家詳細(xì)介紹了Unity3D Shader實(shí)現(xiàn)鏡子效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05C#使用oledb導(dǎo)出數(shù)據(jù)到excel的方法
這篇文章主要介紹了C#使用oledb導(dǎo)出數(shù)據(jù)到excel的方法,結(jié)合實(shí)例形式分析了C#操作oledb導(dǎo)出數(shù)據(jù)的相關(guān)技巧與注意事項(xiàng),需要的朋友可以參考下2016-06-06c#動(dòng)態(tài)改變webservice的url訪問(wèn)地址
這篇文章主要介紹了c#動(dòng)態(tài)改變webservice的url訪問(wèn)地址,需要的朋友可以參考下2014-03-03C# MeasureString測(cè)量字符串函數(shù)的使用方法
這篇文章主要介紹了C# MeasureString測(cè)量字符串函數(shù)的使用方法,需要的朋友可以參考下2014-10-10