本文通过示例介绍了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>

参考

C# - List.Sort()自定义排序方法的更多相关文章

  1. Collections.sort自定义排序的使用方法

    Collections.sort自定义排序的使用方法 总结:Collections可以对List进行排序:如果想对Map进行排序,可以将Map转化成List,进行排序: public static v ...

  2. [转载]EF或LINQ 查询时使用IN并且根据列表自定义排序方法

    原文地址:EF或LINQ 查询时使用IN并且根据列表自定义排序方法作者:李明川 EF和LINQ改变了原有的手写SQL时期的一些编码方法,并且增强了各数据库之间的移植性简化了开发时的代码量和难度,由于很 ...

  3. List<T>集合的Sort自定义排序用法简单解析

    List<T>集合的Sort自定义排序用法简单解析: 如下:一系列无序数字,如果想要他们倒序排列,则使用如下代码: 那么如何理解这段代码呢? (x,y)表示相邻的两个对象,如果满足条件:x ...

  4. hdu 1263 水果 结构的排序+sort自定义排序

    水果 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submissi ...

  5. EF或LINQ 查询时使用IN并且根据列表自定义排序方法

    EF和LINQ改变了原有的手写SQL时期的一些编码方法,并且增强了各数据库之间的移植性简化了开发时的代码量和难度,由于很多人不熟,经常会碰到一些写SQL语句时经常会用到的一些方法,而使用EF或LINQ ...

  6. c++ stl sort 自定义排序函数cmp要遵循 strict weak ordering

    满足strict weak ordering的运算符能够表达其他所有的逻辑运算符(logical operator): <(a, b)  : (a < b) <=(a, b): !( ...

  7. [LeetCode] Custom Sort String 自定义排序的字符串

    S and T are strings composed of lowercase letters. In S, no letter occurs more than once. S was sort ...

  8. 007_对go语言中的自定义排序sort的小练习

    在go语言基础知识中,有个知识点是go语言的自定义排序,我在学习完之后,自己做了一些小练习和总结. 首先按照惯例,还是呈上代码演示: package main import "fmt&quo ...

  9. 【转】c++中Vector等STL容器的自定义排序

    如果要自己定义STL容器的元素类最好满足STL容器对元素的要求    必须要求:     1.Copy构造函数     2.赋值=操作符     3.能够销毁对象的析构函数    另外:     1. ...

随机推荐

  1. Spring面试专题之aop

    1.背景 aop是编程中非常非常重要的一种思想,在spring项目中用的场景也非常广 2.面试问题 2.1.简单的面试问题 1.什么是aop,aop的作用是什么? 面向切面编程(AOP)提供另外一种角 ...

  2. 安装centos6.10时,安装完成重启报错error 15,file not found

    今天在一台老式联想服务器上安装centos6.10操作系统,安装完成,重启时,出现报错 error 15, file not found...... 在百度上搜索到进grub编辑,可还是无法解决问题, ...

  3. MySQL 加锁和死锁解析

    目录 产生死锁的必要条件 锁是加在那里的? 操作与加锁的对照关系 Insert Delete Update GAP锁 什么时候加next-key lock? Insert Intention Lock ...

  4. 逆向破解之160个CrackMe —— 028

    CrackMe —— 028 160 CrackMe 是比较适合新手学习逆向破解的CrackMe的一个集合一共160个待逆向破解的程序 CrackMe:它们都是一些公开给别人尝试破解的小程序,制作 c ...

  5. django 统计表

    1. 复杂版 统计,通过跨表查询和timedate模块过滤找到 from django.db.models import Count class TongJiView(View): def today ...

  6. MySQL体系结构与存储引擎

    MySQL 体系结构 先看 MySQL 数据库的体系结构,如下图所示. MySQL 体系结构由 Client Connectors 层.MySQL Server 层及存储引擎层组成. Client C ...

  7. Django Model的外键自关联‘self'和设置'unique_together'

    在django的model定义中,有时需要某个Field引用当前定义的Model,比如一个部门(Department)的Model,它有一个字段是上级部门(super_department),上级部门 ...

  8. USACO Buying Feed, II

    洛谷 P2616 [USACO10JAN]购买饲料II Buying Feed, II 洛谷传送门 JDOJ 2671: USACO 2010 Jan Silver 2.Buying Feed, II ...

  9. jdbc笔记2

    private static String driver; private static String url; private static String username; private sta ...

  10. es4x 调用其他三方jar 包

    es4x 使用了graalvm 作为运行时环境,所以即拥有vertx 的强大,又拥有了与java 代码便捷的通信能力 以下是一个简单的测试,同时也简单说明下es4x 的es4x-launcher.ja ...