集合的排序—— Sort
方法
Array
类提供了 Sort
静态方法,使用快排算法对集合中的元素进行排序。
List<T>
泛型类提供了 Sort
方法,使用快排。
不使用自定义的排序
注意:使用无参数重载的
Sort
方法,需要实现IComparable
接口。简单类型System.String
和System.Int32
等实现IComparable
接口,所以可以对包含这些类型的元素的数组进行排序。
|
|
输出
|
|
自定义规则的排序
传入比较器实例
Array
和 List<T>
泛型类的 Sort
方法都有接受实现 IComparer
接口的类的实例对象的重载。
显示定义比较器类
定义类继承于 Comparer<T>
泛型类,避免拆箱装箱的额外开销,并且保证类型安全,并且实现 Compare(T, T)
方法:
注意:也可以继承于
IComparer
和IComparer<T>
接口,但是这不是Microsoft 建议的做法:
“建议从 Comparer类派生,而不是实现 IComparer 接口,因为 Comparer 该类提供方法的显式接口实现 IComparer.Compare 和 Default 获取对象的默认比较器的属性。”
|
|
返回值的规则为:
- 当
x
应该在y
的 前面 的时候(也就是x
小于y
),返回小于0的数字(-1) - 当
x
应该在y
的 后面 的时候(也就是x
大于y
),返回大于0的数字(1) - 当
null
参与比较时不应该引发异常,且为null
的对象应在其它对象 前面(也就是说 小于 任何其它对象)
另请参阅:
IComparer 接口 (System.Collections) | Microsoft Docs
IComparer
Comparer
“Comparer
使用 Comparer<T>.Create
方法和匿名函数创建比较器
Create
方法用指定的比较创建一个比较器。
该方法的参数是一个 Comparison<T>
类型的委托。可以使用 lambda 表达式直接创建一个匿名函数委托。
|
|
或者直接
|
|
关于 lambda 表达式可以看我的这篇笔记:CSharp的委托、lambda 表达式和事件 - CSharp笔记 —— 博客 | Gaein nidb 的网站
箭头前的 x
y
为两个参数,类型为自动推断的int(如果编译器不能推断可以手动加上类型来指定),只有一个参数的时候可以省略箭头前面的括号。
箭头后为表达式体,只有一行语句的时候可以在箭头后直接书写语句,该语句的返回值将作为匿名方法返回值。如果有多行语句,使用花括号框成代码块,并且使用 return
关键字返回值。
变量 comparer
为 Comparer<int>
的实例,作为参数传入 Array.Sort
方法即可。
另请参阅:
Comparer
Comparer
传入委托的比较方法
Array
类和 List<T>
泛型类也都有 Comparison<T>
类型参数的重载,所以可以直接使用 lambda 创建匿名函数传入 Sort
方法。
|
|
没错,把 Create
方法的参数扔这里就好了(那我前面是什么废话)。
LINQ的排序—— OrderBy
方法
OrderBy
方法用于升序排序,orderby
子句会被编译器转换为对 OrderBy 方法的调用。
不使用自定义的排序
使用重载 OrderBy<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>)
来使用默认的比较器进行升序排序:
|
|
输出为
|
|
自定义规则的排序
LINQ 的 OrderBy
方法没有像 Array
和 List<T>
一样的传入 Comparison<T>
类型委托的重载。它只提供了重载 OrderBy<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>, IComparer<TKey>)
。因此,我们不能在参数表里传入 lambda 表达式创建匿名方法来比较。只能创建类并继承于 Comparer<T>
,或者使用 Comparer<T>.Create
方法并传入用于比较的匿名方法。
当需要多次进行这种比较时推荐创建自定义的类,并且实例化一个对象多次使用。或者创建一个变量来存储 Comparer<T>.Create
创建的对象。
比如:
|
|
注意:这种情况实际上是不需要自定义比较器的,为了演示才这么写的(因为我懒得想例子)