C#中的IComparable 和 IComparer 接口,实现列表中的对象比较和排序
借豆瓣某博主的话先对这两个接口进行一个解释:
IComparable在要比较的对象的类中实现,可以比较该对象和另一个对象
IComparer在一个单独的类中实现,可以比较任意两个对象。
如果已经支持 IComparer 的类型 (如 字符串 或 整数) 的数组可以对该数组进行排序而无需提供 IComparer 任何显式引用。在这种情况下该数组的元素强制转换为您 IComparer(Comparer.Default) 的默认实现。但是,如果您想要提供您自定义的对象进行排序或比较功能,则必须实现这些接口的一项或两项。
IComparable
IComparable 的作用是提供了一种比较两个对象的特定类型的方法。这是必需的如果您想要为对象提供任何排序功能。视为 IComparable 提供您的对象的默认排序次序。例如对于如果您有一个您的类型的对象的数组,并在该数组上调用 Sort 方法 IComparable 在排序过程中提供对象的比较。实现 IComparable 界面时, 必须实现 CompareTo 方法,如下所示:
1 int IComparable.CompareTo(object obj) 2 { 3 car c=(car)obj; 4 return String.Compare(this.make,c.make); 5 }
方法中的比较是不同的要比较的值数据类型 depending on。因为选择了比较属性是字符串,此示例中使用 String.Compare。
IComparer
IComparer 的角色是提供附加的比较机制。例如对于您可能需要提供几个字段或属性,在类中的顺序升序和降序在同一字段或两者。
使用 IComparer 是一个包含两个步骤的过程:
1)声明一个类实现 IComparer,然后实现比较方法:
1 private class sortYearAscendingHelper : IComparer 2 { 3 int IComparer.Compare(object a, object b) 4 { 5 car c1=(car)a; 6 car c2=(car)b; 7 if (c1.year > c2.year) 8 return 1; 9 if (c1.year < c2.year) 10 return -1; 11 else 12 return 0; 13 } 14 }
2)声明一个返回 IComparer 对象的实例的方法:
1 public static IComparer sortYearAscending() 2 { 3 return (IComparer) new sortYearAscendingHelper(); 4 }
在此的示例为第二个参数时,调用重载的 Array.Sort 方法接受 IComparer 使用对象。IComparer 的使用并不限于数组。它将被接受作为许多不同的集合和控件类中的参数。
而在List<T>中已经有了排序的方法了.Sort(参数),参数为比较器,共有四种重载。
Name | Description |
---|---|
Sort() | Sorts the elements in the entireList<T> using the default comparer. |
Sort(Comparison<T>) | Sorts the elements in the entireList<T> using the specifiedSystem.Comparison<T>. |
Sort(IComparer<T>) | Sorts the elements in the entireList<T> using the specified comparer. |
Sort(Int32, Int32, IComparer<T>) | Sorts the elements in a range of elements in List<T> using the specified comparer. |
第一种就是默认排序,只对常见的类型比如int,float,double,string等可以自身比较的类型。默认升序排序。、
第二种为Comparison<T>,此处是指定比较的模式,只需要写一个简单的比较函数即可,比如:
1 private static int CompareDinosByLength(string x, string y)//这里的参数一般是要比较的List内的元素 2 { 3 if (x == null) 4 { 5 if (y == null) 6 return 0; 7 else 8 return -1; 9 } 10 else 11 { 12 if (y == null) 13 return 1; 14 else 15 { 16 int retval = x.Length.CompareTo(y.Length); 17 if (retval != 0) 18 return retval; 19 else 20 return x.CompareTo(y); 21 } 22 } 23 } 24 25 int static Main() 26 { 27 List<string> dinosaurs = new List<string>(); 28 dinosaurs.Add("Pachycephalosaurus"); 29 dinosaurs.Add("Amargasaurus"); 30 dinosaurs.Add(""); 31 dinosaurs.Add(null); 32 dinosaurs.Add("Mamenchisaurus"); 33 dinosaurs.Add("Deinonychus"); 34 Display(dinosaurs); 35 36 Console.WriteLine("\nSort with generic Comparison<string> delegate:"); 37 dinosaurs.Sort(CompareDinosByLength); 38 }
第三种相对复杂一点,需要新设置一个比较器,并且实现接口,实现其中的函数,比如:
1 public class DinoComparer: IComparer<string> 2 { 3 public int Compare(string x, string y) 4 { 5 if (x == null) 6 { 7 if (y == null) 8 return 0; 9 else 10 return -1; 11 } 12 else 13 { 14 if (y == null) 15 return 1; 16 else 17 { 18 int retval = x.Length.CompareTo(y.Length); 19 20 if (retval != 0) 21 return retval; 22 else 23 return x.CompareTo(y); 24 } 25 } 26 } 27 } 28 29 public class Example 30 { 31 public static void Main() 32 { 33 List<string> dinosaurs = new List<string>(); 34 dinosaurs.Add("Pachycephalosaurus"); 35 dinosaurs.Add("Amargasaurus"); 36 dinosaurs.Add("Mamenchisaurus"); 37 dinosaurs.Add("Deinonychus"); 38 39 DinoComparer dc = new DinoComparer(); 40 dinosaurs.Sort(dc); 41 }
第四种则是在第三中的基础之上添加指定的索引内的排序。
那么在写好的比较器上怎么实现逆转排序呢?就是如果原先是正序,那么想要反序如何?看排序函数的返回值都是int类型,所以想要反序只需要在调用时前面加 - (负)即可。一般正序排序的返回值:-1代表前小后大,0代表相等,1代表前大后小,排序效果为从小到大。
调用时是使用函数名调用,所以必须写两个函数了。使用Linq的排序可以使用前加符号的方式:http://www.tuicool.com/articles/aqU3eee