聲明:本文爲www.cnc6.cn原創,轉載時請註明出處,謝謝!ide
本文做者文采欠佳,文字表達等方面不是很好,但實際的代碼例子是很是實用的,請做參考。函數
1、先準備要使用的類:this
一、Person類:spa
class Person { public string Name { set; get; } public int Age { set; get; } public string Gender { set; get; } public override string ToString() => Name; }
二、準備要使用的List,用於分組(GroupBy):code
List<Person> personList = new List<Person> { new Person { Name = "P1", Age = 18, Gender = "Male" }, new Person { Name = "P2", Age = 19, Gender = "Male", }, new Person { Name = "P2", Age = 17,Gender = "Female", } };
2、第一種用法:對象
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);
官方釋義:根據指定的鍵選擇器函數對序列中的元素進行分組。blog
咱們要分組的集合爲source,集合內每一個元素的類型爲TSource,這裏第一個參數keySelector的類型爲Func<TSource, TKey>,用於將TSource元素按照由此委託返回的類型TKey進行分組,結果爲一個已分好組的集合(集合中的集合)。element
編寫客戶端試驗代碼以下:字符串
var groups = personList.GroupBy(p => p.Gender); foreach (var group in groups) { Console.WriteLine(group.Key); foreach(var person in group) { Console.WriteLine($"\t{person.Name},{person.Age}"); } }
以上代碼指定的KeySelector是Person類的Gender屬性,所以,以上會按照Gender(性別)進行分組,咱們使用兩個嵌套的foreach循環將分組的內容打印到控制檯。get
由於groups返回的類型爲IEnumerable<IGouping<TKey,TSource>>,所以以上返回的類型爲IEnumerable<IGouping<string,Person>>。
IGouping<string,Person>是已經分組後的集合,內部集合元素爲Person,且IGouping有一個Key屬性,類型爲string(指的是Gender屬性類型),用於分組的標識。
輸出結果以下:
其等價的LINQ語句爲:
var groups = from p in personList group p by p.Gender;
以上的意思能夠這樣理解:從personList取出p,並對p進行分組,使用分組的依據(Key)爲p.Gender,並將分組的結果存儲到pGroup,並將分組的結果選擇出來合併成一個集合。
3、第二種用法:
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer);
官方釋義:根據指定的鍵選擇器函數對序列中的元素進行分組,並使用指定的比較器對鍵進行比較。
這種比第一種方法多了一個參數,那就是一個相等比較器,目的是爲了當TKey爲自定義的類時,GroupBy能根據TKey指定的類根據相等比較器進行分組,
所以,自定義類如何進行分組,GroupBy是不知道的,須要本身定義本身的相等比較器。
首先,將personList更改以下(下劃線部分):
List<Person> personList = new List<Person> { new Person { Name = "P1", Age = 18, Gender = "Male" }, new Person { Name = "P1", Age = 19, Gender = "Male", }, new Person { Name = "P3", Age = 17,Gender = "Female", } };
其次,增長一個相等比較器類,用於對Person進行分組:
class PersonEqualityComparer : IEqualityComparer<Person> { public bool Equals(Person x, Person y) => x.Name == y.Name; public int GetHashCode(Person obj) => obj.Name.GetHashCode(); }
其中定義瞭如何對一個Person相等性定義,只要實現IEqualityComparer<Person>便可,這裏以Name做爲Person類是否相同的依據。
最後,如今咱們對Person類進行分組,編寫客戶端實驗代碼以下:
var groups = personList.GroupBy(p => p, new PersonEqualityComparer()); foreach (var group in groups) { Console.WriteLine(group.Key.ToString()); foreach(var person in group) { Console.WriteLine($"\t{person.Age},{person.Gender}"); } }
以上的分組依據是Person類,並運用了本身定義的Person類相同比較器,只要Name相同,就分爲一組,
輸出結果以下:
4、第三種用法:
public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector);
官方釋義:根據指定的鍵選擇器函數對序列中的元素進行分組,而且經過使用指定的函數對每一個組中的元素進行投影。
這個比第一種用法多了一個elementSelector,第一種用法是對集合自己按照TKey分組,並將本身(TSource)添加到分組內,而當前的用法則能夠選擇本身想要添加到分組內的元素類型。
編寫客戶端實驗代碼以下:
var groups = personList.GroupBy(p => p.Gender, p=>p.Name); foreach (var group in groups) { Console.WriteLine(group.Key.ToString()); foreach(var name in group) { Console.WriteLine($"\t{name}"); } }
以上代碼是按照p.Gender進行分組,並將p.Name做爲組內的元素。
輸出結果以下:
其等價的LINQ語句爲:
var groups = from p in personList group p.Name by p.Gender;
5、第四種用法:
public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IEnumerable<TSource>, TResult> resultSelector);
官方釋義:根據指定的鍵選擇器函數對序列中的元素進行分組,而且從每一個組及其鍵中建立結果值。
這個跟以前的用法都不一樣,以前的用法都是將結果進行分組,並返回IGrouping<TKey,TSource>對象,而當前用法則是返回本身定義的類型(TResult),在返回本身定義類型以前,將會傳入兩個參數,一個是TKey,爲分組時指定的對象,另一個則是IEnumerable<TSource>,爲分組後的內部對象集合。
編寫客戶端實驗代碼以下:
string GetPersonInfo(string gender, IEnumerable<Person> persons) { string result = $"{gender}:\t"; foreach (var p in persons) { result += $"{p.Name},{p.Age}\t"; } return result; } var results = personList.GroupBy(p => p.Gender,(g, ps) => GetPersonInfo(g,ps)); foreach (var result in results) { Console.WriteLine(result); }
GetPersonInfo爲局部方法,見於C#7.0及以上。
以上代碼將分組後的內容(一個是TKey,爲p.Gender,另一個是IEnumerable<TSource>,爲IEnumerable<Person>)做爲字符串輸出,所以,將返回的類型爲字符串集合。
輸出結果以下:
其等價的LINQ語句爲:
var results = from p in personList group p by p.Gender into pGroup select GetPersonInfo(pGroup.Key, pGroup);
6、第五種用法:
public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer);
官方釋義:根據鍵選擇器函數對序列中的元素進行分組。經過使用比較器對鍵進行比較,而且經過使用指定的函數對每一個組的元素進行投影。
與第三種用法基本相同,只是多了一個相等比較器,用於分組的依據。
使用第二種用法的personList及PersonEqualityComparer,編寫客戶端實驗代碼以下:
var groups = personList.GroupBy(p => p, p => new { p.Age,p.Gender },new PersonEqualityComparer()); foreach (var group in groups) { Console.WriteLine(group.Key.ToString()); foreach (var name in group) { Console.WriteLine($"\t{name.Age},{name.Gender}"); } }
以上代碼的分組依據是Person,PersonEqualityComparer則是做爲Person分組的比較器,每一個組內爲一個匿名類型集合。
輸出結果以下:
7、第六種用法:
public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IEnumerable<TSource>, TResult> resultSelector, IEqualityComparer<TKey> comparer);
官方釋義:根據指定的鍵選擇器函數對序列中的元素進行分組,而且從每一個組及其鍵中建立結果值。經過使用指定的比較器對鍵進行比較。
與第四種用法基本相同,只是多了一個相等比較器,用於分組的依據。
使用第二種用法的personList及PersonEqualityComparer,編寫客戶端實驗代碼以下:
string GetPersonInfo(Person person, IEnumerable<Person> persons) { string result = $"{person.ToString()}:\t"; foreach (var p in persons) { result += $"{p.Age},{p.Gender}\t"; } return result; } var results = personList.GroupBy(p => p, (p, ps) => GetPersonInfo(p, ps),new PersonEqualityComparer()); foreach (var result in results) { Console.WriteLine(result); }
以上代碼的分組依據是Person,PersonEqualityComparer則是做爲Person分組的比較器,每一個組內爲一個Person集合,並將返回類型爲string的字符串輸出。
輸出結果以下:
8、第七種用法:
public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector);
官方釋義:根據指定的鍵選擇器函數對序列中的元素進行分組,而且從每一個組及其鍵中建立結果值。經過使用指定的函數對每一個組的元素進行投影。
與第四種方法很相似,只是對分組內的元素進行選擇,原有爲TSource,現改成TElement。
編寫客戶端實驗代碼以下:
string GetPersonInfo(string gender, IEnumerable<string> names) { string result = $"{gender}:\t"; foreach (var name in names) { result += $"{name}\t"; } return result; } var results = personList.GroupBy(p => p.Gender, (p=>p.Name) ,(g, ns) => GetPersonInfo(g, ns)); foreach (var result in results) { Console.WriteLine(result); }
以上代碼將使用Gender分組,並將分組後的信息組合成一條字符串,並輸出到控制檯。
輸出結果以下:
9、第八種用法:
public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector, IEqualityComparer<TKey> comparer);
官方釋義: 根據指定的鍵選擇器函數對序列中的元素進行分組,而且從每一個組及其鍵中建立結果值。經過使用指定的比較器對鍵值進行比較,而且經過使用指定的函數對每一個組的元素進行投影。
與第七種用法基本相同,只是多了一個相等比較器,用於分組的依據。
使用第二種用法的personList及PersonEqualityComparer,編寫客戶端實驗代碼以下:
var results = personList.GroupBy(p => p, (p=>new { p.Age,p.Gender}), (p, ns) => { string result = $"{p.ToString()}:\t"; foreach (var n in ns) { result += $"{n.Age},{p.Gender}\t"; } return result; },new PersonEqualityComparer()); foreach (var result in results) { Console.WriteLine(result); }
以上代碼將使用Person分組,使用Person比較器做爲分組的依據,並將分組後的信息組合成一條字符串,並輸出到控制檯。
輸出結果以下: