改善C#程序的方法-(3)比较器和LINQ排序

打印 上一主题 下一主题

主题 911|帖子 911|积分 2733

一 创建对象时考虑实现比较器

假设有这样的场景,有一个40个人的学生列表,业务中需针对学生的成绩来进行排序。
可以考虑用IComparable接口和ICompare接口实现:
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         var stus = new List<Student>();
  6.         stus.Add(new Student() { Name = "zhangsan", EnglishGrades = 80.5, MathGrades = 90 });
  7.         stus.Add(new Student() { Name = "lisi", EnglishGrades = 74, MathGrades = 91 });
  8.         stus.Add(new Student() { Name = "wangwu", EnglishGrades = 94, MathGrades = 85.5 });
  9.         stus.Add(new Student() { Name = "zhaoliu", EnglishGrades = 88.5, MathGrades = 86 });
  10.       
  11.         stus.Sort();
  12.         Console.WriteLine("使用默认比较器排序:");
  13.         foreach (var stu in stus)
  14.         {
  15.             Console.WriteLine($"Name:{stu.Name},\tEnglish:{stu.EnglishGrades},\tMath:{stu.MathGrades}");
  16.         }
  17.         
  18.         stus.Sort(new MathComparer());
  19.         Console.WriteLine("使用自定义比较器排序:");
  20.         foreach (var stu in stus)
  21.         {
  22.             Console.WriteLine($"Name:{stu.Name},\tEnglish:{stu.EnglishGrades},\tMath:{stu.MathGrades}");
  23.         }
  24.         Console.ReadLine();
  25.     }
  26. }
  27. //Student通过IComparable接口,实现默认比较器
  28. class Student : IComparable<Student>
  29. {
  30.     public string Name { get; set; }
  31.     public double EnglishGrades { get; set; }
  32.     public double MathGrades { get; set; }
  33.     public int CompareTo(Student stu)
  34.     {
  35.         if (EnglishGrades > stu.EnglishGrades)
  36.         {
  37.             return 1;
  38.         }
  39.         else if (EnglishGrades == stu.EnglishGrades)
  40.         {
  41.             return 0;
  42.         }
  43.         else
  44.         {
  45.             return -1;
  46.         }
  47.         //return EnglishGrades.CompareTo(stu.EnglishGrades); double类型的默认比较方法
  48.     }
  49. }
  50. //通过IComparer接口实现自定义的比较器
  51. class MathComparer : IComparer<Student>
  52. {
  53.     public int Compare(Student x, Student y)
  54.     {
  55.         return x.MathGrades.CompareTo(y.MathGrades);
  56.     }
  57. }
复制代码
输出:
  1. 使用默认比较器排序:
  2. Name:lisi,      English:74,     Math:91
  3. Name:zhangsan,  English:80.5,   Math:90
  4. Name:zhaoliu,   English:88.5,   Math:86
  5. Name:wangwu,    English:94,     Math:85.5
  6. 使用自定义比较器排序:
  7. Name:wangwu,    English:94,     Math:85.5
  8. Name:zhaoliu,   English:88.5,   Math:86
  9. Name:zhangsan,  English:80.5,   Math:90
  10. Name:lisi,      English:74,     Math:91
复制代码
 二 使用LINQ取代集合中的比较器

上述的方法实现的排序存在2个问题:

  • 可扩展性太低,如果存在新的排序要求,就必须实现新的比较器;
  • 对代码的侵入性太高,为类型继承了接口,新增了方法。
LINQ提供了类似于SQL的语法来实现遍历、筛选和投影集合的强大功能,可以实现上述的排序要求。
  1. static void Main(string[] args)
  2. {
  3.     var stus = new List<Student>();
  4.     stus.Add(new Student() { Name = "zhangsan", EnglishGrades = 80.5, MathGrades = 90 });
  5.     stus.Add(new Student() { Name = "lisi", EnglishGrades = 74, MathGrades = 91 });
  6.     stus.Add(new Student() { Name = "wangwu", EnglishGrades = 94, MathGrades = 85.5 });
  7.     stus.Add(new Student() { Name = "zhaoliu", EnglishGrades = 88.5, MathGrades = 86 });
  8.     var orderByStus = from s in stus orderby s.EnglishGrades select s;
  9.     //orderByStus = stus.OrderBy(s => s.EnglishGrades);
  10.     foreach (var stu in orderByStus)
  11.     {
  12.         Console.WriteLine($"Name:{stu.Name},\tEnglish:{stu.EnglishGrades},\tMath:{stu.MathGrades}");
  13.     }
  14.     Console.WriteLine();
  15.    
  16.     orderByStus = from s in stus orderby s.MathGrades select s;
  17.     //orderByStus = stus.OrderBy(s => s.MathGrades);
  18.     foreach (var stu in orderByStus)
  19.     {
  20.         Console.WriteLine($"Name:{stu.Name},\tEnglish:{stu.EnglishGrades},\tMath:{stu.MathGrades}");
  21.     }
  22.     Console.ReadLine();
  23. }
复制代码
LINQ此功能的实现本身是借助于FCL泛型集合的比较器、迭代器和索引器。LINQ封装了这些功能,让我们使用更加方便。
在命名空间System.Linq下的Enumerable方法中为泛型集合提供了很多扩展方法。
如排序中使用到的OrderBy方法:
  1.    public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);
复制代码
它为继承了IEnumerable接口的集合提供排序的功能。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

三尺非寒

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表