List集合操作二:排序
本文继续讲解List<T>之排序操作,C#范型List类的Sort方法有四种形式,分别是:
1、不带有任何参数的Sort方法----Sort();
2、带有比较器参数的Sort方法 ----Sort(IComparer<T>)
3、带有比较代理方法参数的Sort方法----Sort(Comparison<(Of <(T>)>))
4、带有比较起参数,可以指定排序范围的Sort方法----Sort(Int32, Int32 IComparer(T))
首先对IComparable.CompareTo 方法进行一下介绍:
MSDN解释:将当前实例与同一类型的另一个对象进行比较,并返回一个整数,该整数指示当前实例在排序顺序中的位置是位于另一个对象之前、之后还是与其位置相同。
原型:int CompareTo (Object obj)
参数 obj:与此实例进行比较的对象。
返回值:一个 32 位有符号整数,指示要比较的对象的相对顺序。
返回值的含义如下:
小于0 此实例小于 obj;位置在obj之前。
等于0 此实例等于 obj;位置在obj相同。
大于0 此实例大于 obj;位置在obj之后。
下面我们通过一个控制台实例来分别介绍这四种方法:
第一种方法元素继承IComparable:
* 使用这种方法不是对List中的任何元素对象都可以进行排序
* List中的元素对象必须继承IComparable接口并且要实现IComparable接口中的CompareTo()方法
* 在CompareTo()方法中要自己实现对象的比较规则
我们还沿用第一篇的实体类Player 并使其继承IComparable接口
using System; namespace ListDemo2 { public class Player : IComparable<Player> { public Player(int id, string name, string team) { this.Id = id; this.Name = name; this.Team = team; } public int Id { get; set; } public string Name { get; set; } public string Team { get; set; } #region IComparable<Model> 成员 /// <summary> /// 实现的IComparable接口,用于进行比较。因为排序是建立在比较的基础之上的。 /// </summary> /// <param name="otherP">另外一个Player</param> /// <returns> /// 小于0 此实例按排序顺序在 otherP 前面 /// 等于0 此实例与otherP 在排序顺序中出现的位置相同 /// 大于0 此实例按排序顺序在 otherP 后面 /// </returns> public int CompareTo(Player otherP) { //只要调换位置就可以调整排序的方式 //return this.Id.CompareTo(otherP.Id); //正序 return otherP.Id.CompareTo(this.Id); //倒序 } #endregion } }
定义一个集合类PlayerList
using System.Collections.Generic; namespace ListDemo2 { public class PlayerList : List<Player> { public PlayerList() { this.Add(new Player(1, "科比-布莱恩特", "湖人队")); this.Add(new Player(2, "保罗-加索尔", "湖人队")); this.Add(new Player(3, "拉玛尔-奥多姆", "湖人队")); this.Add(new Player(4, "德克-诺维茨基", "小牛队")); this.Add(new Player(5, "杰森-特里", "小牛队")); this.Add(new Player(6, "肖恩-马里昂", "小牛队")); this.Add(new Player(7, "凯文-加内特", "凯尔特人队")); } } }
Main函数代码:
using System; using System.Collections.Generic; namespace ListDemo2 { class Program { static void Main(string[] args) { //1、不带有任何参数的Sort方法 PlayerList players = new PlayerList(); Action<Player> listSort = delegate(Player p) { Console.WriteLine(string.Format("队员Id={0} | 队员名称={1} | 所属球队={2} ", p.Id, p.Name, p.Team)); }; Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("第一种不带有任何参数的Sort方法"); Console.WriteLine("实现元素继承ICompare实现_队员ID从大到小排列:"); Console.ForegroundColor = ConsoleColor.Yellow; players.Sort(); players.ForEach(listSort); Console.ReadKey(); } } }
执行结果如下图:
第二种带有比较器参数的Sort方法
* List中的元素对象不需要继承IComparable接口
* 但需要额外创建一个对象的比较器
我们重新定义个Student 实体类:
namespace ListDemo2 { public class Student { public Student(int id, string name, float score) { this.Id = id; this.Name = name; this.Score = score; } public int Id { get; set; } public string Name { get; set; } public float Score { get; set; } }
再定义个StudentList集合类:
using System.Collections.Generic; namespace ListDemo2 { public class StudentList : List<Student> { public StudentList() { this.Add(new Student(1, "小明", 88.5f)); this.Add(new Student(2, "小红", 90)); this.Add(new Student(3, "小兰", 93)); this.Add(new Student(4, "小花", 72.5f)); this.Add(new Student(5, "小猫", 88)); this.Add(new Student(6, "小狗", 63)); } } }
我们定义一个StudentCompare类继承 IComparer接口:
using System; using System.Collections.Generic; namespace ListDemo2 { public class StudentCompare : IComparer<Student> { //比较器的枚举,可以按照Id 和 Score 进行排序 public enum CompareType { Id, Score } private CompareType compareType; public StudentCompare(CompareType compareType) { this.compareType = compareType; } public int Compare(Student x, Student y) { if ((x == null) || (y == null)) return -1; switch (compareType) { case CompareType.Id: return x.Id.CompareTo(y.Id); //成绩从大到小排列 case CompareType.Score: return y.Score.CompareTo(x.Score); default: return -1; } } } }
Main函数代码:
using System; using System.Collections.Generic; namespace ListDemo2 { class Program { static void Main(string[] args) { //2、带有比较器参数的Sort方法 ---Sort(IComparer<T>) StudentList students1 = new StudentList(); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("第二种带有比较器参数的Sort方法"); Console.WriteLine("实现_学生成绩从大到小排列:"); Console.ForegroundColor = ConsoleColor.Yellow; students1.Sort(new StudentCompare(StudentCompare.CompareType.Score)); students1.ForEach(s => Console.WriteLine(string.Format("Id={0} | 姓名={1} | 成绩={2} ", s.Id, s.Name, s.Score))); Console.ReadKey(); } } }
执行结果如下图:
第三种方法需要编写一个对象排序比较的方法
* 对List中的元素对象没有特殊的要求
* 但在比较方法中需要实现对象比较规则
* 这个方法实现后,就可以把这方名字作为参数委托给List的Sort方法
* Sort方法在排序时会执行这个方法对List中的对象进行比较
我们写个为学生成绩从小到大排序的比较方法:
private static int SortStudentCompare(Student stu1, Student stu2) { return stu1.Score.CompareTo(stu2.Score); }
Main 函数代码:
using System; using System.Collections.Generic; namespace ListDemo2 { class Program { static void Main(string[] args) { //3、带有比较代理方法参数的Sort方法 StudentList student2 = new StudentList(); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("带有比较代理方法参数的Sort方法"); Console.WriteLine("实现_学生成绩从小到大排列:"); Console.ForegroundColor = ConsoleColor.Yellow; student2.Sort(SortStudentCompare); student2.ForEach(s => Console.WriteLine(string.Format("Id={0} | 姓名={1} | 成绩={2} ", s.Id, s.Name, s.Score))); Console.ReadKey(); } } }
执行结果如图:
第四种方法其实是一种扩展,可以对List内部分数据进行排序
比如我们可以为StudentList的前三名学生的成绩进行从大到小的排序:
using System; using System.Collections.Generic; namespace ListDemo2 { class Program { static void Main(string[] args) { //4、带有比较起参数,可以指定排序范围的Sort方法 StudentList student3 = new StudentList(); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("带有比较起参数,可以指定排序范围的Sort方法"); Console.WriteLine("实现_前3名学生成绩从大到小排列:"); Console.ForegroundColor = ConsoleColor.Yellow; student3.Sort(0, 3, new StudentCompare(StudentCompare.CompareType.Score)); student3.ForEach(s => Console.WriteLine(string.Format("Id={0} | 姓名={1} | 成绩={2} ", s.Id, s.Name, s.Score))); Console.ReadKey(); } } }
执行结果如下图: