本文通过示例介绍了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. Linux从入门到放弃、零基础入门Linux(第三篇):在虚拟机vmware中安装linux(二)超详细手把手教你安装centos6分步图解

    一.继续在vmware中安装centos6.9 本次安装是进行最小化安装,即没有图形化界面的安装,如果是新手,建议安装带图形化界面的centos, 具体参考Linux从入门到放弃.零基础入门Linux ...

  2. SELECT语句基础

    列的查询 语法1-1 基本的SELECT语句 SELECT <列名>,... FROM <表名>; 语法1-2 查询出表中所有的列 SELECT * FROM  <表名& ...

  3. 内核中dump_stack的实现原理(3) —— 内核函数printk的实现

      参考内核文档: Documentation/printk-formats.txt   在内核中使用dump_stack的时候可以看到如下用法: static inline void print_i ...

  4. Spring中@Autowired、@Resource和@Inject注解的使用和区别

    在使用Spring进行项目开发的时候,会大量使用到自动装配,那自动装配是什么呢?简单来说:Spring 利用依赖注入(DI)功能,完成SpringIOC容器中各个组件之间的依赖关系赋值管理. 下面介绍 ...

  5. vs2017 curl7.6编译

    nmake /f Makefile.vc mode=static VC=15 MACHINE=x86 nmake /f Makefile.vc mode=dll VC=15 MACHINE=x86 c ...

  6. Java 中的各种锁

    table th:first-of-type { width: 100px; } 锁的类型 锁的实现 乐观锁 在数据库中可以使用version版本号去实现:在Java中是使用CAS(Compare A ...

  7. Install PDFtk on Ubuntu

    https://linuxhint.com/install_pdftk_ubuntu/ PDF is an integral part of our everyday life. It’s a doc ...

  8. USACO Slowing down

    洛谷 P2982 [USACO10FEB]慢下来Slowing down 洛谷传送门 JDOJ 2684: USACO 2010 Feb Gold 3.Slowing down JDOJ传送门 Des ...

  9. Java 基本类型、封装类型、常量池、基本运算

    基本数据类型: byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0 short:短整型,在内存中占16位,即2个字节,取值范围-32768~3 ...

  10. 将HashMap转换为List

    背景 ​ SpringBoot中,使用@RquestBody注解 hashMap 接收多个参数的json字符串数据,包括一个数组和一个int值.数组中为一个个的对象组成. 问题 ​ 使用 map.ge ...