[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方法有三个重载方法。
对自定义类型排序
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 }
总结
从下班弄到现在,一直整理笔记。泛型集合的排序选一个顺手的就行。
-
博客地址:http://www.cnblogs.com/wolf-sun/
博客版权:如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步! 再次感谢您耐心的读完本篇文章。