当前位置:首页 > C#数组排序与对象大小比较

C#数组排序与对象大小比较

点击次数:1922  更新日期:2011-11-04

从个小例子开始:

\r\n
  1. int[]?intArray?=?new?int[]{2,3,6,1,4,5}; ?
  2. Array.Sort(intArray); ?
  3. Array.ForEach<int>(intArray,(i)=>Console.WriteLine(i));?
\r\n

这个例子定义了一个int数组,然后使用Array.Sort(arr)静态方法对此数组进行排序,最后输出排序后的数组。以上例子将毫无意外的依次输出1,2,3,4,5,6.

\r\n

为什么Array的Sort方法可以正确的对int数组进行排序呢,我们自定义类可以吗?试试看,如下代码:

\r\n
  1. public?class?Student ?
  2. { ?
  3. public?int?Age?{?get;?set;?} ?
  4. public?string?Name?{?get;?set;?} ?
  5. public?int?Score?{?get;?set;?} ?
  6. } ?
  7. static?void?Main(string[]?args) ?
  8. { ?
  9. Student[]?students?=?new?Student[]{ ?
  10. new?Student(){Age?=?10,Name="张三",Score=70}, ?
  11. new?Student(){Age?=?12,Name="李四",Score=97}, ?
  12. new?Student(){Age?=?11,Name="王五",Score=80}, ?
  13. new?Student(){Age?=?9,Name="赵六",Score=66}, ?
  14. new?Student(){Age?=?12,Name="司马",Score=90}, ?
  15. }; ?
  16. Console.WriteLine("--------------默认排序输出--------"); ?
  17. Array.Sort(students); ?
  18. Array.ForEach(students,(s)=>Console.WriteLine(string.Format("{0}{1,2}岁了,他的分数是{2,3}",s.Name,s.Age,s.Score))); ?
  19. Console.Read(); ?
  20. }?
\r\n

我们定义了Student类然后同样对他的数组进行排序,程序正确的编译通过,但是运行出错,运行时抛出了异常:System.InvalidOperationException{"Failed to compare two elements in the array."},这个异常的InnerException是ArgumentException{"At least one object must implement IComparable."};运行时异常说明:我们要使用Array.Sort(arr)静态方法,必须得保证数组中有一个元素实现IComparable接口。既然如此我们就让Student类实现IComparable接口.

\r\n
  1. public?class?Student?:IComparable ?
  2. { ?
  3. public?int?Age?{?get;?set;?} ?
  4. public?string?Name?{?get;?set;?} ?
  5. public?int?Score?{?get;?set;?} ?
  6. ///? ?
  7. ///?实现IComparable接口,用Age做比较 ?
  8. ///? ?
  9. ///?比较对象 ?
  10. ///?比较结果 ?
  11. public?int?CompareTo(object?obj) ?
  12. { ?
  13. if?(obj?is?Student) ?
  14. { ?
  15. return?Age.CompareTo(((Student)obj).Age); ?
  16. } ?
  17. return?1; ?
  18. } ?
  19. }?
\r\n

在Student类中实现了IComparable接口,在CompareTo方法中比较Student的Age属性,这一次再次编译运行,程序正常的输出了按照年龄排序的Student数组。

\r\n

假如说我们要对Student的Score属性进行排序该怎么办呢? Student类实现的IComparable接口只能按照一种属性排序呀。

\r\n

这个是很容易实现的.net的类库开发者早为我们准备了另一个接口IComparer接口用来实现比较类型T的两个实例。如下StudentScoreComparer类实现了对Student按照Score属性比较的IComparer

\r\n
  1. public?class?StudentScoreComparer?:?IComparer ?
  2. { ?
  3. public?int?Compare(Student?x,?Student?y) ?
  4. { ?
  5. return?x.Score.CompareTo(y.Score); ?
  6. } ?
  7.  }?
\r\n

现在我们可以使用下面代码对Student数组按照Score属性进行排序:

\r\n

Console.WriteLine("----------按分数排序输出------------");

\r\n

Array.Sort(students, new StudentScoreComparer());

\r\n

Array.ForEach(students, (s) => Console.WriteLine(string.Format("{0}{1,2}岁了,他的分数是{2,3}", s.Name, s.Age, s.Score)));

\r\n

不过一个简单的按照Score属性排序,再定义一个类是不是有点大题小作呀,有没有更好的办法呢?当然有. .net为我们准备了比较对象大小的委托Comparison我们可以使用拉姆达表达式或者匿名委托直接排序,如下代码实现:

\r\n
  1. Console.WriteLine("----------按分数排序输出----------"); ?
  2. Array.Sort(students,?(s1,?s2)?=>?s1.Score.CompareTo(s2.Score)); ?
  3. Array.ForEach(students,?(s)?=>?Console.WriteLine(string.Format("{0}{1,2}岁了,他的分数是{2,3}",?s.Name,?s.Age,?s.Score)));?
\r\n

完整代码示例如下:

\r\n
  1. using?System; ?
  2. using?System.Collections.Generic; ?
  3. using?System.Linq; ?
  4. using?System.Text; ?
  5. namespace?SortingInCSharp ?
  6. { ?
  7. class?Program ?
  8. { ?
  9. public?class?Student?:?IComparable ?
  10. { ?
  11. public?int?Age?{?get;?set;?} ?
  12. public?string?Name?{?get;?set;?} ?
  13. public?int?Score?{?get;?set;?} ?
  14. ///? ?
  15. ///?实现IComparable接口,用Age做比较 ?
  16. ///? ?
  17. ///?比较对象 ?
  18. ///?比较结果 ?
  19. public?int?CompareTo(object?obj) ?
  20. { ?
  21. if?(obj?is?Student) ?
  22.  { ?
  23. return?Age.CompareTo(((Student)obj).Age); ?
  24. } ?
  25. return?1; ?
  26. } ?
  27. } ?
  28. static?void?Main(string[]?args) ?
  29. { ?
  30. Student[]?students?=?new?Student[]{ ?
  31. new?Student(){Age?=?10,Name="张三",Score=70}, ?
  32. new?Student(){Age?=?12,Name="李四",Score=97}, ?
  33. new?Student(){Age?=?11,Name="王五",Score=80}, ?
  34. new?Student(){Age?=?9,Name="赵六",Score=66}, ?
  35. new?Student(){Age?=?12,Name="司马",Score=90}, ?
  36. }; ?
  37. Console.WriteLine("--------------默认排序输出--------"); ?
  38. Array.Sort(students); ?
  39. Array.ForEach(students,?(s)?=>?Console.WriteLine(string.Format("{0}{1,2}岁了,他的分数是{2,3}",?s.Name,?s.Age,?s.Score))); ?
  40. Console.WriteLine("----------按分数排序输出------------"); ?
  41. Array.Sort(students,?new?StudentScoreComparer()); ?
  42. Array.ForEach(students,?(s)?=>?Console.WriteLine(string.Format("{0}{1,2}岁了,他的分数是{2,3}",?s.Name,?s.Age,?s.Score))); ?
  43. Console.WriteLine("----------按分数排序输出----------"); ?
  44. Array.Sort(students,?(s1,?s2)?=>?s1.Score.CompareTo(s2.Score)); ?
  45. Array.ForEach(students,?(s)?=>?Console.WriteLine(string.Format("{0}{1,2}岁了,他的分数是{2,3}",?s.Name,?s.Age,?s.Score))); ?
  46. Console.Read(); ?
  47. } ?
  48. public?class?StudentScoreComparer?:?IComparer ?
  49. { ?
  50. public?int?Compare(Student?x,?Student?y) ?
  51. { ?
  52. return?x.Score.CompareTo(y.Score); ?
  53. } ?
  54. } ?
  55. } ?
  56. }?
\r\n

总结:

\r\n

在C#中有三个关于比较对象大小的接口,分别是IComparable、IComparable和IComparer。 IComparable和IComparable是类本身实现的在实例之间比较大小的行为定义。IComparer是定义在被比较类之外的专门比较两个T类型对象大小的行为,另外还有一个用于比较的委托定义Comparison可以让我们用拉姆达表达式或者匿名委托或方法更方便的排序。

\r\n