C# - List.Sort()自定义排序方法
本文通过示例介绍了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>
参考
- IComparable接口 - Microsoft
- Comparison委托 - Microsoft
- IComparer接口 - Microsoft
- IComparable和IComparer接口和自定义比较器 - My_Pure
C# - List.Sort()自定义排序方法的更多相关文章
- Collections.sort自定义排序的使用方法
Collections.sort自定义排序的使用方法 总结:Collections可以对List进行排序:如果想对Map进行排序,可以将Map转化成List,进行排序: public static v ...
- [转载]EF或LINQ 查询时使用IN并且根据列表自定义排序方法
原文地址:EF或LINQ 查询时使用IN并且根据列表自定义排序方法作者:李明川 EF和LINQ改变了原有的手写SQL时期的一些编码方法,并且增强了各数据库之间的移植性简化了开发时的代码量和难度,由于很 ...
- List<T>集合的Sort自定义排序用法简单解析
List<T>集合的Sort自定义排序用法简单解析: 如下:一系列无序数字,如果想要他们倒序排列,则使用如下代码: 那么如何理解这段代码呢? (x,y)表示相邻的两个对象,如果满足条件:x ...
- hdu 1263 水果 结构的排序+sort自定义排序
水果 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submissi ...
- EF或LINQ 查询时使用IN并且根据列表自定义排序方法
EF和LINQ改变了原有的手写SQL时期的一些编码方法,并且增强了各数据库之间的移植性简化了开发时的代码量和难度,由于很多人不熟,经常会碰到一些写SQL语句时经常会用到的一些方法,而使用EF或LINQ ...
- c++ stl sort 自定义排序函数cmp要遵循 strict weak ordering
满足strict weak ordering的运算符能够表达其他所有的逻辑运算符(logical operator): <(a, b) : (a < b) <=(a, b): !( ...
- [LeetCode] Custom Sort String 自定义排序的字符串
S and T are strings composed of lowercase letters. In S, no letter occurs more than once. S was sort ...
- 007_对go语言中的自定义排序sort的小练习
在go语言基础知识中,有个知识点是go语言的自定义排序,我在学习完之后,自己做了一些小练习和总结. 首先按照惯例,还是呈上代码演示: package main import "fmt&quo ...
- 【转】c++中Vector等STL容器的自定义排序
如果要自己定义STL容器的元素类最好满足STL容器对元素的要求 必须要求: 1.Copy构造函数 2.赋值=操作符 3.能够销毁对象的析构函数 另外: 1. ...
随机推荐
- Linux从入门到放弃、零基础入门Linux(第三篇):在虚拟机vmware中安装linux(二)超详细手把手教你安装centos6分步图解
一.继续在vmware中安装centos6.9 本次安装是进行最小化安装,即没有图形化界面的安装,如果是新手,建议安装带图形化界面的centos, 具体参考Linux从入门到放弃.零基础入门Linux ...
- SELECT语句基础
列的查询 语法1-1 基本的SELECT语句 SELECT <列名>,... FROM <表名>; 语法1-2 查询出表中所有的列 SELECT * FROM <表名& ...
- 内核中dump_stack的实现原理(3) —— 内核函数printk的实现
参考内核文档: Documentation/printk-formats.txt 在内核中使用dump_stack的时候可以看到如下用法: static inline void print_i ...
- Spring中@Autowired、@Resource和@Inject注解的使用和区别
在使用Spring进行项目开发的时候,会大量使用到自动装配,那自动装配是什么呢?简单来说:Spring 利用依赖注入(DI)功能,完成SpringIOC容器中各个组件之间的依赖关系赋值管理. 下面介绍 ...
- vs2017 curl7.6编译
nmake /f Makefile.vc mode=static VC=15 MACHINE=x86 nmake /f Makefile.vc mode=dll VC=15 MACHINE=x86 c ...
- Java 中的各种锁
table th:first-of-type { width: 100px; } 锁的类型 锁的实现 乐观锁 在数据库中可以使用version版本号去实现:在Java中是使用CAS(Compare A ...
- Install PDFtk on Ubuntu
https://linuxhint.com/install_pdftk_ubuntu/ PDF is an integral part of our everyday life. It’s a doc ...
- USACO Slowing down
洛谷 P2982 [USACO10FEB]慢下来Slowing down 洛谷传送门 JDOJ 2684: USACO 2010 Feb Gold 3.Slowing down JDOJ传送门 Des ...
- Java 基本类型、封装类型、常量池、基本运算
基本数据类型: byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0 short:短整型,在内存中占16位,即2个字节,取值范围-32768~3 ...
- 将HashMap转换为List
背景 SpringBoot中,使用@RquestBody注解 hashMap 接收多个参数的json字符串数据,包括一个数组和一个int值.数组中为一个个的对象组成. 问题 使用 map.ge ...