本文通过示例介绍了C#中典型容器List.Sort()的自定义排序方法,进而引出了C#中自定义排序的核心接口及方法

项目地址:自定义Sort方法 - SouthBegonia's Github

List.Sort() 为我们提供了4种自定义排序方法,通过对这些方法改进我们可以轻松做到对多参数、多规则的复杂排序:

List<T>.Sort();
List<T>.Sort(IComparer<T> Comparer);
List<T>.Sort(int index, int count, IComparer<T> Comparer);
List<T>.Sort(Comparison<T> comparison);

项目背景

存在People类,包含Name、Age属性,在客户端中创建List保存多个实例,对List根据Name和Age参数进行排序:

class People
{
public People(string name, int age) { Name = name; Age = age; }
public string Name { get; set; }
public int Age { get; set; }
} // 客户端
class Client
{
static void Main(string[] args)
{
List<People> peopleList = new List<People>();
peopleList.Add(new People("张三", 22));
peopleList.Add(new People("张三", 24));
peopleList.Add(new People("李四", 18));
peopleList.Add(new People("王五", 16));
peopleList.Add(new People("王五", 30));
}
}

List.Sort()

该方法为系统默认的方法,单一参数时会默认进行升序排序。但遇到多参数(Name、Age)排序时,我们需要对该默认方法进行修改。

  • 方法:People类继承IComparable,实现CompareTo()方法
  • IComparable<T>:定义由值类型或类实现的通用比较方法,旨在创建特定于类型的比较方法以对实例进行排序。
  • 原理:自行实现的CompareTo()方法会在list.Sort()内部进行元素两两比较,最终实现排序
class People : IComparable<People>
{
public People(string name, int age) { Name = name;Age = age; }
public string Name { get; set; }
public int Age { get; set; } // list.Sort()时会根据该CompareTo()进行自定义比较
public int CompareTo(People other)
{
if (this.Name != other.Name)
{
return this.Name.CompareTo(other.Name);
}
else if (this.Age != other.Age)
{
return this.Age.CompareTo(other.Age);
}
else return 0;
}
} // 客户端
peopleList.Sort(); // OUTPUT:
// 李四 18
// 王五 16
// 王五 30
// 张三 22
// 张三 24

List.Sort(IComparer Comparer)

区别于上述继承IComparable的方法,该方法不可在People内继承实现IComparer接口,而是需要新建比较方法类进行接口实现

  • 方法:新建PeopleComparer类、继承IComparer接口、实现Compare()方法
  • 原理:list.Sort()将PeopleComparer类的实例作为参数,在内部使用Compare()方法进行两两比较,最终实现排序(注:上述方法为CompareTo(),此处为Compare()方法)
// 自定义比较方法类
class PeopleComparer : IComparer<People>
{
// 区别于CompareTo()单参数,此处为双参数
public int Compare(People x, People y)
{
if (x.Name != y.Name)
{
return x.Name.CompareTo(y.Name);
}
else if (x.Age != y.Age)
{
return x.Age.CompareTo(y.Age);
}
else return 0;
}
} // 客户端
// 传入参数为自定义比较类的实例
peopleList.Sort(new PeopleComparer()); // OUTPUT:
// 李四 18
// 王五 16
// 王五 30
// 张三 22
// 张三 24

同理,List<T>.Sort(int index, int count, IComparer<T> Comparer) 方法的参数:待排元素起始索引、待排元素个数、排序方法

List.Sort(Comparison comparison)

区别于上述继承接口的方法,此方法的参数为 泛型委托 Comparison<T>

  • 委托原型:public delegate int Comparison<in T>(T x, T y);
  • 方法:依照委托的使用方法,首先创建委托实例MyComparison,并绑定到自定义的比较方法PeopleComparison()上,最终调用list.Sort()时 将委托实例传入
  • 原理:list.Sort()根据传入的委托方法,进行两两元素比较最终实现排序
// 客户端
class Client
{
// 自定义比较方法
public static int PeopleComparison(People p1, People p2)
{
if (p1.Name != p2.Name)
{
return p1.Name.CompareTo(p2.Name);
}
else if (p1.Age != p2.Age)
{
return p1.Age.CompareTo(p2.Age);
}
else return 0;
} static void Main(string[] args)
{
/* 创建list ... */ // 创建委托实例并绑定
Comparison<People> MyComparison = PeopleComparison; // 传入该实例实现比较方法
peopleList.Sort(MyComparison); // OUTPUT:
// 李四 18
// 王五 16
// 王五 30
// 张三 22
// 张三 24
}
}

此外,既然Comparison<T>是泛型委托,则完全可以用 Lambda表达式 进行描述:

// Lambda表达式实现Comparison委托
peopleList.Sort((p1, p2) =>
{
if (p1.Name != p2.Name)
{
return p2.Name.CompareTo(p1.Name);
}
else if (p1.Age != p2.Age)
{
return p2.Age.CompareTo(p1.Age);
}
else return 0;
}); // OUTPUT:
// 张三 24
// 张三 22
// 王五 30
// 王五 16
// 李四 18

总结

虽然本文仅使用了List<T>一种容器对Sort()方法进行阐述,但是不同容器的使用Sort()的方法大相径庭,因为核心的原理都是应用两种接口及泛型委托

  • 两种接口IComparable<T> 、 IComparer<T>
  • 泛型委托Comparison<T>

参考

最新文章

  1. Linux Shell 脚本调试
  2. 第三章:Git使用入门
  3. Linux添加主机路由
  4. Visual Studio 2015速递(1)——C#6.0新特性怎么用
  5. java校验时间格式 HH:MM
  6. 找到多个与名为“Index”的控制器匹配的类型的解决方法!
  7. kvm介绍
  8. hdu 4786 Fibonacci Tree (2013ACMICPC 成都站 F)
  9. lua之mysql编程
  10. Installing Windows Identity Foundation on Windows 8 - The Certificate for the signer of the message is invalid or not found.
  11. 《A First Course in Probability》-chaper7-期望的性质-相关系数
  12. 创建第一个freemarker
  13. 洞穴勘测(bzoj 2049)
  14. SQLite错误总结 error code 19: constraint failed
  15. 回味Python2.7——笔记1
  16. 【Android 应用开发】对Android体系结构的理解--后续会补充
  17. apigateway-kong(二)admin-api(结合实例比官网还详细)
  18. python学习之Numpy.genfromtxt
  19. python socket原理 及socket如何使(tcp udp协议)
  20. Redis+Keepalived高可用环境部署记录

热门文章

  1. 轻量级.Net ORM SqlSuger项目实战
  2. 如果再聘请一位会css的美工,那要你还有什么用?
  3. fastadmin CMS等系列插件安装不成功的问题
  4. Flask 中字典数据返回(jsonify)
  5. php静态化介绍
  6. update的where条件要把索引的字段带上,要不然就全表锁
  7. 【转】Pandas学习笔记(七)plot画图
  8. NVIDIA-GPU归入K8S集群管理的安装文档--第二版
  9. 201871010115——马北《面向对象程序设计JAVA》第二周学习总结
  10. 2019 Nowcoder Multi-University Training Contest 4 E Explorer