[c#基礎]泛型集合的自定義類型排序


引用

最近總有種感覺,自己復習的進度總被項目中的問題給耽擱了,項目中遇到的問題,不總結又不行,只能將復習基礎方面的東西放后再放后。一直沒研究過太深奧的東西,過去一年一直在基礎上打轉,寫代碼,反編譯,不停的重復。一直相信,在你不知道要干嘛的時候,浮躁的時候,不如回到最基礎的東西上,或許換種思考方式,會有不一樣的收獲。

泛型集合List<T>排序

先看一個簡單的例子,int類型的集合:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 namespace Wolfy.SortDemo
 7 {
 8     class Program
 9     {
10         static void Main(string[] args)
11         {
12             List<int> list = new List<int>() {  3, 4, 5, -2, -5, 11, 23,  };
13             Console.WriteLine("排序前....");
14             foreach (int item in list)
15             {
16                 Console.Write(item+"\t");
17             }
18             list.Sort();
19             Console.WriteLine();
20             Console.WriteLine("排序后....");
21             foreach (int item in list)
22             {
23                 Console.Write(item+"\t");
24             }
25             Console.Read();
26         }
27     }
28 }

經sort方法之后,采用了升序的方式進行排列的。

集合的Sort方法

 1  //
 2         // 摘要: 
 3         //     使用默認比較器對整個 System.Collections.Generic.List<T> 中的元素進行排序。
 4         //
 5         // 異常: 
 6         //   System.InvalidOperationException:
 7         //     默認比較器 System.Collections.Generic.Comparer<T>.Default 找不到 T 類型的 System.IComparable<T>
 8         //     泛型接口或 System.IComparable 接口的實現。
 9         public void Sort();
10         //
11         // 摘要: 
12         //     使用指定的 System.Comparison<T> 對整個 System.Collections.Generic.List<T> 中的元素進行排序。
13         //
14         // 參數: 
15         //   comparison:
16         //     比較元素時要使用的 System.Comparison<T>。
17         //
18         // 異常: 
19         //   System.ArgumentNullException:
20         //     comparison 為 null。
21         //
22         //   System.ArgumentException:
23         //     在排序過程中,comparison 的實現會導致錯誤。 例如,將某個項與其自身進行比較時,comparison 可能不返回 0。
24         public void Sort(Comparison<T> comparison);
25         //
26         // 摘要: 
27         //     使用指定的比較器對整個 System.Collections.Generic.List<T> 中的元素進行排序。
28         //
29         // 參數: 
30         //   comparer:
31         //     比較元素時要使用的 System.Collections.Generic.IComparer<T> 實現,或者為 null,表示使用默認比較器 System.Collections.Generic.Comparer<T>.Default。
32         //
33         // 異常: 
34         //   System.InvalidOperationException:
35         //     comparer 為 null,且默認比較器 System.Collections.Generic.Comparer<T>.Default 找不到
36         //     T 類型的 System.IComparable<T> 泛型接口或 System.IComparable 接口的實現。
37         //
38         //   System.ArgumentException:
39         //     comparer 的實現導致排序時出現錯誤。 例如,將某個項與其自身進行比較時,comparer 可能不返回 0。
40         public void Sort(IComparer<T> comparer);
41         //
42         // 摘要: 
43         //     使用指定的比較器對 System.Collections.Generic.List<T> 中某個范圍內的元素進行排序。
44         //
45         // 參數: 
46         //   index:
47         //     要排序的范圍的從零開始的起始索引。
48         //
49         //   count:
50         //     要排序的范圍的長度。
51         //
52         //   comparer:
53         //     比較元素時要使用的 System.Collections.Generic.IComparer<T> 實現,或者為 null,表示使用默認比較器 System.Collections.Generic.Comparer<T>.Default。
54         //
55         // 異常: 
56         //   System.ArgumentOutOfRangeException:
57         //     index 小於 0。 - 或 - count 小於 0。
58         //
59         //   System.ArgumentException:
60         //     index 和 count 未指定 System.Collections.Generic.List<T> 中的有效范圍。 - 或 - comparer
61         //     的實現導致排序時出現錯誤。 例如,將某個項與其自身進行比較時,comparer 可能不返回 0。
62         //
63         //   System.InvalidOperationException:
64         //     comparer 為 null,且默認比較器 System.Collections.Generic.Comparer<T>.Default 找不到
65         //     T 類型的 System.IComparable<T> 泛型接口或 System.IComparable 接口的實現。
66         public void Sort(int index, int count, IComparer<T> comparer);
Sort()

可見sort方法有三個重載方法。

對自定義類型排序

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Wolfy.SortDemo
 8 {
 9     public class Person
10     {
11         public string Name { set; get; }
12         public int Age { set; get; }
13    }
14 }

對Person進行sort后輸出,就會出現如下異常:

對自定義的Person類型進行排序,出現異常。那為什么int類型就沒有呢?可以反編譯一下,你會發現:

可見int類型是實現了IComparable這個接口的。那么如果讓自定義類型Person也可以排序,那么試試實現該接口。

修改Person類

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Wolfy.SortDemo
 8 {
 9     public class Person : IComparable
10     {
11         public string Name { set; get; }
12         public int Age { set; get; }
13 
14         /// <summary>
15         /// 實現接口中的方法
16         /// </summary>
17         /// <param name="obj"></param>
18         /// <returns></returns>
19         public int CompareTo(object obj)
20         {
21             Person p = obj as Person;
22             //因為int32實現了接口IComparable,那么int也有CompareTo方法,直接調用該方法就行
23             return this.Age.CompareTo(p.Age);
24         }
25     }
26 }

CompareTo方法的參數為要與之進行比較的另一個同類型對象,返回值為int類型,如果返回值大於0,表示第一個對象大於第二個對象,如果返回值小於0,表示第一個對象小於第二個對象,如果返回0,則兩個對象相等。
定義好默認比較規則后,就可以通過不帶參數的Sort方法對集合進行排序。

測試結果:

以上采用的sort()方法排序的結果。

 實際使用中,經常需要對集合按照多種不同規則進行排序,這就需要定義其他比較規則,可以在Compare方法中定義,該方法屬於IComparer<T>泛型接口,請看下面的代碼:

 1 namespace Wolfy.SortDemo
 2 {
 3     public class PersonNameDesc:IComparer<Person>
 4     {
 5         //存放排序器實例
 6         public static PersonNameDesc NameDesc = new PersonNameDesc();
 7         public int Compare(Person x, Person y)
 8         {
 9             return System.Collections.Comparer.Default.Compare(x.Name, y.Name);
10         }
11     }
12 }

Compare方法的參數為要進行比較的兩個同類型對象,返回值為int類型,返回值處理規則與CompareTo方法相同。其中的Comparer.Default返回一個內置的Comparer對象,用於比較兩個同類型對象。

    下面用新定義的這個比較器對集合進行排序:

 1  class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             List<Person> list = new List<Person>()
 6             {
 7                 new Person(){Name="a",Age=2},
 8                 new Person(){Name="d",Age=9},
 9                 new Person(){Name="b",Age=3},
10                 new Person(){Name="c",Age=10}
11             };
12        
13             list.Sort(PersonNameDesc.NameDesc);
14             foreach (Person p in list)
15             {
16                 Console.WriteLine(p.Name + "\t" + p.Age);
17             }
18             Console.Read();
19         }
20     }

測試結果:

 Sort(int index, int count, IComparer<T> comparer)

同上面的類似,只是這個是取范圍的。

Sort(Comparison<T> comparison)

sort方法的一個重載是Comparison<T>類型的參數,那么Comparison到底是什么東東呢?,說實話,不F12還真發現不了。

 1 #region 程序集 mscorlib.dll, v4.0.0.0
 2 // C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\mscorlib.dll
 3 #endregion
 4 
 5 namespace System
 6 {
 7     // 摘要: 
 8     //     表示比較同一類型的兩個對象的方法。
 9     //
10     // 參數: 
11     //   x:
12     //     要比較的第一個對象。
13     //
14     //   y:
15     //     要比較的第二個對象。
16     //
17     // 類型參數: 
18     //   T:
19     //     要比較的對象的類型。
20     //
21     // 返回結果: 
22     //     一個有符號整數,指示 x 與 y 的相對值,如下表所示。 值 含義 小於 0 x 小於 y。 0 x 等於 y。 大於 0 x 大於 y。
23     public delegate int Comparison<in T>(T x, T y);
24 }

看到這里就該笑了,委托啊,那么豈不是可以匿名委托,豈不是更方便啊。那么排序可以這樣了。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 namespace Wolfy.SortDemo
 7 {
 8     class Program
 9     {
10         static void Main(string[] args)
11         {
12             List<Person> list = new List<Person>()
13             {
14                 new Person(){Name="a",Age=2},
15                 new Person(){Name="b",Age=9},
16                 new Person(){Name="c",Age=3},
17                 new Person(){Name="d",Age=10}
18             };
19             //匿名委托
20             list.Sort((a,b)=>a.Age-b.Age);
21             foreach (Person p in list)
22             {
23                 Console.WriteLine(p.Name + "\t" + p.Age);
24             }
25             Console.Read();
26         }
27     }
28 }

結果:

使用Linq排序

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 namespace Wolfy.SortDemo
 7 {
 8     class Program
 9     {
10         static void Main(string[] args)
11         {
12             List<Person> list = new List<Person>()
13             {
14                 new Person(){Name="a",Age=2},
15                 new Person(){Name="d",Age=9},
16                 new Person(){Name="b",Age=3},
17                 new Person(){Name="c",Age=10}
18             };
19             var l = from p in list
20                     orderby p.Age descending
21                     select p;
22             //list.Sort(PersonNameDesc.NameDesc);
23             foreach (Person p in l)
24             {
25                 Console.WriteLine(p.Name + "\t" + p.Age);
26             }
27             Console.Read();
28         }
29     }
30 }

總結

 從下班弄到現在,一直整理筆記。泛型集合的排序選一個順手的就行。 


免責聲明!

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



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