在Linq中排序操作可以按照一個或多個關鍵字對序列進行排序。其中第一個排序關鍵字為主要關鍵字,第二個排序關鍵字為次要關鍵字。Linq排序操作共包含以下5個基本的操作。
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>"); } }
看看運行結果:
我們看到和我們預想的是一樣的。那麼大家可能有些疑問,為什麼OrderBy是升序排序呢?
我們來從源碼解析一下:
我們看到OrderBy裡面最終調用了一個函數OrderedEnumerable,那麼我們再來看看這個OrderedEnumerable函數:
看到這個函數有一個參數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類的比較參數是,該元素取反,所以排序結果應該就成了降序排序了。我們看看測試結果:
嗯和我們預想的一樣,這個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方法的傳入參數不同。
我們看到這個傳入的是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>"); } }
看看測試結果:
嗯結果和預想的一樣。
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>"); } }
看看結果:
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>"); } }
運行結果:
看確實是反轉了。
再看一個本來無序的例子。
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>"); } }
運行結果:
可以看出,只是把序列的元素反轉了,並不會進行升序或者降序排序。
我們來看看內部實現,內部實現其實很簡單:
就是對序列反向輸出。