Linq查询操作之排序操作
2016-04-22 11:09
267 查看
在Linq中排序操作可以按照一个或多个关键字对序列进行排序。其中第一个排序关键字为主要关键字,第二个排序关键字为次要关键字。Linq排序操作共包含以下5个基本的操作。
1、OrderBy操作,根据排序关键字对序列进行升序排序
2、OrderByDescending操作,根据排序关键字对序列进行降序排序
3、ThenBy操作,对次要关键字进行升序排序
4、ThenByDescending操作,对次要关键字进行降序排序
5、Reverse操作,将序列中的元素进行反转
那么下面我们就逐一来分析一下每个排序操作。
OrderBy操作
OrderBy操作是按照主关键字对序列进行升序排序的操作。Enumerable类的OrderBy()原型如下:
其中source表示数据源,keySelector表示获取排序的关键字的函数,comparer参数表示排序时的比较函数。TSource表示数据源的类型,TKey表示排序关键字的类型。下面我们用两种方式来比较排序,第一种按照前面讲的查询表达式来排序,第二种用现在的排序操作来排序,其实结果都是一样的。
看看运行结果:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422101230070-2067575182.png)
我们看到和我们预想的是一样的。那么大家可能有些疑问,为什么OrderBy是升序排序呢?
我们来从源码解析一下:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422101417835-1627504080.png)
我们看到OrderBy里面最终调用了一个函数OrderedEnumerable,那么我们再来看看这个OrderedEnumerable函数:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422101552991-877372901.png)
看到这个函数有一个参数descending,我们OrderBy方法给这个参数传了false,那么就表示非降序排序,就是升序排序。可想而知,OrderByDescending操作,给这个参数传值应该是true。
第二个原型里面有个comparer参数,那么我们来看看怎么用:既然是IComparer接口类型的参数,那么我们就定义一个实现了Icomparer接口的类型:
我们看到,我们定义的CompareIntegers类的比较参数是,该元素取反,所以排序结果应该就成了降序排序了。我们看看测试结果:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422103308366-1347979261.png)
嗯和我们预想的一样,这个comparer函数就是我们自定义的比较方式。
OrderByDescending操作
OrderByDescending和我们上面的OrderBy操作相似,最终都是调用OrderedEnumerable只是传入的descending参数的值不同。看看OrderByDescending的原型:
也有两个原型,跟OrderBy的原型一模一样,只是最终调用OrderedEnumerable方法的传入参数不同。
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422103838351-2074915798.png)
我们看到这个传入的是true,表示降序排列。所以我个人觉得这两个操作可以合并,然后多一个参数而已。
同样写个例子测试一下:
看看测试结果:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422104039210-1867185790.png)
嗯结果和预想的一样。
ThenBy操作
上面两个排序都是按照主关键字来排序的,下面呢我们就看看什么是按照次要关键字排序。ThenBy 和OrderBy一样是按照升序排序的。来看看原型:
原型和OrderBy一样。但是ThenBy必须要和OrderBy配合使用。就是 必须要先有OrderBy排序,然后再用ThenBy排序。不能够直接用ThenBy排序。
同样我们写个例子一看便知。这个例子呢我们每个序列的每个元素至少要有两个字段,一个做主关键字,一个做次要关键字。我们还是用前面将的UserBaseInfo来创建例子,用ID做主关键字,username做次要关键字。
看看结果:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422105438210-1181933882.png)
ThenByDescending操作
这个是ThenBy的降序排序方式,和前面的用法实质是一样的,我就不详细讲解了,大家可以自己研究一下。
Reverse操作
下面我们就来看看Reverse这个排序。这个排序呢可以说也不算是排序,因为我们知道排序无非就是升序,或者降序。这个其实就是将一个序列进行反转,里面的值如果本来没有顺序,执行这个操作之后,也不会变得有序,只是序列的元素反转。
看看reverse的原型:
测试样例:
运行结果:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422110151241-190871385.png)
看确实是反转了。
再看一个本来无序的例子。
运行结果:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422110447179-1493384892.png)
可以看出,只是把序列的元素反转了,并不会进行升序或者降序排序。
我们来看看内部实现,内部实现其实很简单:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422110720679-2080571879.png)
就是对序列反向输出。
1、OrderBy操作,根据排序关键字对序列进行升序排序
2、OrderByDescending操作,根据排序关键字对序列进行降序排序
3、ThenBy操作,对次要关键字进行升序排序
4、ThenByDescending操作,对次要关键字进行降序排序
5、Reverse操作,将序列中的元素进行反转
那么下面我们就逐一来分析一下每个排序操作。
OrderBy操作
OrderBy操作是按照主关键字对序列进行升序排序的操作。Enumerable类的OrderBy()原型如下:
1、public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) { return new OrderedEnumerable<TSource, TKey>(source, keySelector, null, false); } 2、public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer) { return new OrderedEnumerable<TSource, TKey>(source, keySelector, comparer, false); }
其中source表示数据源,keySelector表示获取排序的关键字的函数,comparer参数表示排序时的比较函数。TSource表示数据源的类型,TKey表示排序关键字的类型。下面我们用两种方式来比较排序,第一种按照前面讲的查询表达式来排序,第二种用现在的排序操作来排序,其实结果都是一样的。
private void OrderByQuery() { int[] ints = new int[] { 1, 3, 5, 4, 7, 6, 8 }; //使用查询表达式来排序 Response.Write("--------------使用查询表达式来排序---------</br>"); var values = from v in ints orderby v select v; foreach (var item in values) { Response.Write(item+"</br>"); } //使用排序操作来排序 Response.Write("--------------使用排序操作来排序---------</br>"); var result = ints.OrderBy(x => x); foreach (var re in result) { Response.Write(re + "</br>"); } }
看看运行结果:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422101230070-2067575182.png)
我们看到和我们预想的是一样的。那么大家可能有些疑问,为什么OrderBy是升序排序呢?
我们来从源码解析一下:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422101417835-1627504080.png)
我们看到OrderBy里面最终调用了一个函数OrderedEnumerable,那么我们再来看看这个OrderedEnumerable函数:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422101552991-877372901.png)
看到这个函数有一个参数descending,我们OrderBy方法给这个参数传了false,那么就表示非降序排序,就是升序排序。可想而知,OrderByDescending操作,给这个参数传值应该是true。
第二个原型里面有个comparer参数,那么我们来看看怎么用:既然是IComparer接口类型的参数,那么我们就定义一个实现了Icomparer接口的类型:
private void OrderByQuery() { int[] ints = new int[] { 1, 3, 5, 4, 7, 6, 8 }; var result = ints.OrderBy(x => x,new CompareIntegers()); foreach (var re in result) { Response.Write(re + "</br>"); } } public class CompareIntegers : IComparer<int> { public int Compare(int i1, int i2) { return -1*(i1 - i2); } }
我们看到,我们定义的CompareIntegers类的比较参数是,该元素取反,所以排序结果应该就成了降序排序了。我们看看测试结果:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422103308366-1347979261.png)
嗯和我们预想的一样,这个comparer函数就是我们自定义的比较方式。
OrderByDescending操作
OrderByDescending和我们上面的OrderBy操作相似,最终都是调用OrderedEnumerable只是传入的descending参数的值不同。看看OrderByDescending的原型:
public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector); public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer);
也有两个原型,跟OrderBy的原型一模一样,只是最终调用OrderedEnumerable方法的传入参数不同。
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422103838351-2074915798.png)
我们看到这个传入的是true,表示降序排列。所以我个人觉得这两个操作可以合并,然后多一个参数而已。
同样写个例子测试一下:
private void OrderByDescendingQuery() { int[] ints = new int[] { 1, 3, 5, 4, 7, 6, 8 }; //使用查询表达式来排序 Response.Write("--------------使用查询表达式来排序---------</br>"); var values = from v in ints orderby v descending select v; foreach (var item in values) { Response.Write(item+"</br>"); } //使用排序操作来排序 Response.Write("--------------使用排序操作来排序---------</br>"); var result = ints.OrderByDescending(x => x); foreach (var re in result) { Response.Write(re + "</br>"); } }
看看测试结果:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422104039210-1867185790.png)
嗯结果和预想的一样。
ThenBy操作
上面两个排序都是按照主关键字来排序的,下面呢我们就看看什么是按照次要关键字排序。ThenBy 和OrderBy一样是按照升序排序的。来看看原型:
public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector); public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer);
原型和OrderBy一样。但是ThenBy必须要和OrderBy配合使用。就是 必须要先有OrderBy排序,然后再用ThenBy排序。不能够直接用ThenBy排序。
同样我们写个例子一看便知。这个例子呢我们每个序列的每个元素至少要有两个字段,一个做主关键字,一个做次要关键字。我们还是用前面将的UserBaseInfo来创建例子,用ID做主关键字,username做次要关键字。
private void ThenByQuery() { IList<UserBaseInfo> users = new List<UserBaseInfo>(); for (int i = 1; i < 10; i++) { users.Add(new UserBaseInfo(i, "user0" + i.ToString(), "user0" + i.ToString() + "@web.com")); } var values = users.OrderBy(u => u.ID).ThenBy(x => x.UserName); foreach (var u in values) { Response.Write("ID:" + u.ID + "</br>" + "username:" + u.UserName + "</br>"); } }
看看结果:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422105438210-1181933882.png)
ThenByDescending操作
这个是ThenBy的降序排序方式,和前面的用法实质是一样的,我就不详细讲解了,大家可以自己研究一下。
Reverse操作
下面我们就来看看Reverse这个排序。这个排序呢可以说也不算是排序,因为我们知道排序无非就是升序,或者降序。这个其实就是将一个序列进行反转,里面的值如果本来没有顺序,执行这个操作之后,也不会变得有序,只是序列的元素反转。
看看reverse的原型:
public static IEnumerable<TSource> Reverse<TSource>(this IEnumerable<TSource> source);
测试样例:
private void ReverseQuery() { IList<UserBaseInfo> users = new List<UserBaseInfo>(); for (int i = 1; i < 10; i++) { users.Add(new UserBaseInfo(i, "user0" + i.ToString(), "user0" + i.ToString() + "@web.com")); } var values = users.Reverse(); foreach (var u in values) { Response.Write("ID:" + u.ID + "</br>" + "username:" + u.UserName + "</br>"); } }
运行结果:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422110151241-190871385.png)
看确实是反转了。
再看一个本来无序的例子。
private void ReverseQuery() { int[] ints = new int[] { 1, 3, 5, 4, 7, 6, 8 }; var result = ints.Reverse(); foreach (var re in result) { Response.Write(re + "</br>"); } }
运行结果:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422110447179-1493384892.png)
可以看出,只是把序列的元素反转了,并不会进行升序或者降序排序。
我们来看看内部实现,内部实现其实很简单:
![](https://images2015.cnblogs.com/blog/352688/201604/352688-20160422110720679-2080571879.png)
就是对序列反向输出。
相关文章推荐
- phantomjs#0基础
- 日常整理的一些网址
- ERROR 1130: Host '' is not allowed to connect to this MySQL server
- 求数列的和
- 反转单向链表 (java 语言实现)
- Mac系统对于NTFS的移动硬盘只能读不能写
- 用Base64.min.js对数据进行加密
- javascript基础六 (DOM优化)
- android中textview中文字显示过长、使其用省略号代替,点击显示全部
- 串口通信代码
- 【c/c++】typedef和define
- 手势用法和详解集合
- 处理百万级以上的数据提高查询速度的方法
- dubbo协议参考
- C++虚函数表
- 常用插件
- Kettle安装与配置
- STL之 map
- 总结一下工作中遇到的NPOI已经在ASP.NET MVC中的使用
- Shell脚本(最坑爹的括号)