List<T>排序
摘要:在面向对象开发过程中我们经常将一组对象放到一个特定集合中,此时我们通常使用泛型集合来存放,常见的如:List 、Dictionary等。在使用这些泛型集合时我们有时需要对其进行排序,下面我们就一块看一下List如何进行排序(像Dictionary也有其相应的排序方式,例如说使用Linq语法方式,今天暂且不说)。
主要内容:
- 初始工作
- 默认排序方式
- 通过自定义比较器进行排序
- 设定排序范围
- 总结
一、初始工作
假设我们有一个Student对象,简单起见这个对象只有三个属性,分别是学好、姓名、年龄。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericCompare
{
class Student
{
public Student()
{
}
public Student(string no, string name, int age)
{
this.No = no;
this.Name = name;
this.Age = age;
}
public string No
{
get;
set;
}
public string Name
{
get;
set;
}
public int Age
{
get;
set;
}
}
}
我们有四个学生,分别存放在List中。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericCompare
{
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>();
students.Add(new Student("001","kenshincui",25));
students.Add(new Student("002", "miaoer", 23));
students.Add(new Student("003", "shenjinjuan", 22));
students.Add(new Student("004", "nieyanxin", 24));
Console.WriteLine("未进行排序之前:");
foreach (Student st in students)
{
Console.WriteLine(st.No+","+st.Name+","+st.Age+";");
}
Console.ReadKey();
}
}
}
很明显我们往students对象中加入学生的时候并没有顺序,下面我们就一起看一下如何对students集合按照年龄由小到大来排序。
二、默认排序方式
如果你查一下List的API的话,我们会看到对于List的Sort方法有四种重载,首先在这里我们说一下第一种,也就是无参数的情况:List.Sort () 。那么我能不能直接对students集合使用Sort()方法进行排序呢?答案是否定的,如果我们使用下面的方法排序的话系统将抛出System.InvalidOperationException异常。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericCompare
{
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>();
students.Add(new Student("001","kenshincui",25));
students.Add(new Student("002", "miaoer", 23));
students.Add(new Student("003", "shenjinjuan", 22));
students.Add(new Student("004", "nieyanxin", 24));
Console.WriteLine("未进行排序之前:");
foreach (Student st in students)
{
Console.WriteLine(st.No+","+st.Name+","+st.Age+";");
}
Console.WriteLine("List.Sort () 排序之后:");
students.Sort();
foreach (Student st in students)
{
Console.WriteLine(st.No + "," + st.Name + "," + st.Age + ";");
}
Console.ReadKey();
}
}
}
执行上面的代码将抛出如下异常
从图中的提示我们可以看出错误原因是由于进行比较的对象并未有任何一个实现IComparable接口,因此也就无法完成排序。事实上对于无参Sort()方法是使用Comparer.Default比较器来排序的,而此比较器进行比较时首先就会检查T是否实现了IComparable泛型接口,如果实现了则使用该实现。否则将坚持是否实现了IComparable接口。如果均未实现则引发InvalidOperationException异常。也就是说如果想使用此方法需要实现ICompara泛型接口或者IComparable接口,因此我们暂且修改一下Student类,实现IComparable接口(除了这个例子职务后面的例子仍然使用第一步我们建立的Student类)。
首先修改Student类,实现IComparable接口:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericCompare
{
class Student:IComparable
{
public Student()
{
}
public Student(string no, string name, int age)
{
this.No = no;
this.Name = name;
this.Age = age;
}
public string No
{
get;
set;
}
public string Name
{
get;
set;
}
public int Age
{
get;
set;
}
#region IComparable 成员
public int CompareTo(object obj)
{
if (obj is Student)
{
Student tempStudent = obj as Student;
return this.Age.CompareTo(tempStudent.Age);
}
throw new NotImplementedException("obj is not a Student!");
}
#endregion
}
}
然后我们再运行程序就会看到可以按照我们的想法去排序了。
接着再使用Sort()排序的话就可以看到如下排序成功的界面:
三、通过自定义比较器进行排序
尽管我们上面说过可以使用Sort()方法排序,但是要求Student必须实现IComparable泛型接口或接口,那么我们有没有其他的方法呢?其实是有的,个人感觉这种方法多数情况下会更好一些。那就是:List.Sort (泛型 Comparison) 和List.Sort (泛型 IComparer) 方法。之所以将这两种重载放到一起来说,是因为二者在使用范围上很类似。首先看一下List.Sort (泛型 Comparison) 方法,此方法的参数是Comparison类型,其实是一个包含两个参数的委托,因此使用此方法,我们只需要定义一个委托,其两个参数均为Student类型,在委托实现的方法比较两个Student对象的Age属性即可。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericCompare
{
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>();
students.Add(new Student("001","kenshincui",25));
students.Add(new Student("002", "miaoer", 23));
students.Add(new Student("003", "shenjinjuan", 22));
students.Add(new Student("004", "nieyanxin", 24));
Console.WriteLine("未进行排序之前:");
foreach (Student st in students)
{
Console.WriteLine(st.No+","+st.Name+","+st.Age+";");
}
Console.WriteLine("List.Sort (泛型 Comparison) 排序之后:");
students.Sort(delegate(Student a, Student b) { return a.Age.CompareTo(b.Age); });
foreach (Student st in students)
{
Console.WriteLine(st.No + "," + st.Name + "," + st.Age + ";");
}
Console.ReadKey();
}
}
}
运行结果(注意此时以及下面的所有例子中Student均不需要实现IComparable泛型接口或接口):
接着我们看一下List.Sort (泛型 IComparer) ,此方法需要一个泛型IComparer接口类型,因此只要定义一个类实现此接口然后再调用此方法即可。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericCompare
{
class StudentCompare :IComparer<Student>
{
public int Compare(Student a, Student b)
{
return a.Age.CompareTo(b.Age);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericCompare
{
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>();
students.Add(new Student("001","kenshincui",25));
students.Add(new Student("002", "miaoer", 23));
students.Add(new Student("003", "shenjinjuan", 22));
students.Add(new Student("004", "nieyanxin", 24));
Console.WriteLine("未进行排序之前:");
foreach (Student st in students)
{
Console.WriteLine(st.No+","+st.Name+","+st.Age+";");
}
Console.WriteLine("List.Sort (泛型 IComparer) 排序之后:");
students.Sort(new StudentCompare());
foreach (Student st in students)
{
Console.WriteLine(st.No + "," + st.Name + "," + st.Age + ";");
}
Console.ReadKey();
}
}
}
运行效果:
四、设定排序范围
虽然上面的方法都实现了泛型集合排序,但是有时我们并不需要对整个集合进行排序而是指对其中一定范围内容的对象进行排序,那么我们就需要使用Sort方法的第四种重载:List.Sort (Int32, Int32, 泛型 IComparer) 。前两个参数分别代表排序的其实位置和排序长度,最后一个参数仍然是泛型IComparer接口类型。上面我们已经定义了StudentComparer类,实现了IComparer接口,这里就可以直接使用了,下面我们只对前三个学生按照年龄由小到大进行排序。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericCompare
{
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>();
students.Add(new Student("001","kenshincui",25));
students.Add(new Student("002", "miaoer", 23));
students.Add(new Student("003", "shenjinjuan", 22));
students.Add(new Student("004", "nieyanxin", 24));
Console.WriteLine("未进行排序之前:");
foreach (Student st in students)
{
Console.WriteLine(st.No+","+st.Name+","+st.Age+";");
}
Console.WriteLine("List.Sort (Int32, Int32, 泛型 IComparer) 排序之后:");
students.Sort(0, 3, new StudentCompare());
foreach (Student st in students)
{
Console.WriteLine(st.No + "," + st.Name + "," + st.Age + ";");
}
Console.ReadKey();
}
}
}
运行效果:
五、总结:
对于List的排序,.Net中给我们提供了很多选择,我们可以根据情况灵活使用。关于其他泛型集合的排序(例如Dictionary)有时间的话我后面也会逐一同大家分享,今天暂且到这里吧!