C#在LINQ中使用GroupBy
一、先準(zhǔn)備要使用的類:
1、Person類:
class Person { public string Name { set; get; } public int Age { set; get; } public string Gender { set; get; } public override string ToString() => Name; }
2、準(zhǔn)備要使用的List,用于分組(GroupBy):
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", } };
二、第一種用法:
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);
官方釋義:根據(jù)指定的鍵選擇器函數(shù)對(duì)序列中的元素進(jìn)行分組。
我們要分組的集合為source,集合內(nèi)每個(gè)元素的類型為TSource,這里第一個(gè)參數(shù)keySelector的類型為Func<TSource, TKey>,用于將TSource元素按照由此委托返回的類型TKey進(jìn)行分組,結(jié)果為一個(gè)已分好組的集合(集合中的集合)。
編寫客戶端試驗(yàn)代碼如下:
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屬性,因此,以上會(huì)按照Gender(性別)進(jìn)行分組,我們使用兩個(gè)嵌套的foreach循環(huán)將分組的內(nèi)容打印到控制臺(tái)。
因?yàn)間roups返回的類型為IEnumerable<IGouping<TKey,TSource>>,因此以上返回的類型為IEnumerable<IGouping<string,Person>>。
IGouping<string,Person>是已經(jīng)分組后的集合,內(nèi)部集合元素為Person,且IGouping有一個(gè)Key屬性,類型為string(指的是Gender屬性類型),用于分組的標(biāo)識(shí)。
輸出結(jié)果如下:
其等價(jià)的LINQ語(yǔ)句為:
var groups = from p in personList group p by p.Gender;
以上的意思可以這樣理解:從personList取出p,并對(duì)p進(jìn)行分組,使用分組的依據(jù)(Key)為p.Gender,并將分組的結(jié)果存儲(chǔ)到pGroup,并將分組的結(jié)果選擇出來(lái)合并成一個(gè)集合。
三、第二種用法:
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer);
官方釋義:根據(jù)指定的鍵選擇器函數(shù)對(duì)序列中的元素進(jìn)行分組,并使用指定的比較器對(duì)鍵進(jìn)行比較。
這種比第一種方法多了一個(gè)參數(shù),那就是一個(gè)相等比較器,目的是為了當(dāng)TKey為自定義的類時(shí),GroupBy能根據(jù)TKey指定的類根據(jù)相等比較器進(jìn)行分組,
因此,自定義類如何進(jìn)行分組,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", } };
其次,增加一個(gè)相等比較器類,用于對(duì)Person進(jìn)行分組:
class PersonEqualityComparer : IEqualityComparer<Person> { public bool Equals(Person x, Person y) => x.Name == y.Name; public int GetHashCode(Person obj) => obj.Name.GetHashCode(); }
其中定義了如何對(duì)一個(gè)Person相等性定義,只要實(shí)現(xiàn)IEqualityComparer<Person>即可,這里以Name作為Person類是否相同的依據(jù)。
最后,現(xiàn)在我們對(duì)Person類進(jìn)行分組,編寫客戶端實(shí)驗(yàn)代碼如下:
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}"); } }
以上的分組依據(jù)是Person類,并運(yùn)用了自己定義的Person類相同比較器,只要Name相同,就分為一組,
輸出結(jié)果如下:
四、第三種用法:
public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector);
官方釋義:根據(jù)指定的鍵選擇器函數(shù)對(duì)序列中的元素進(jìn)行分組,并且通過使用指定的函數(shù)對(duì)每個(gè)組中的元素進(jìn)行投影。
這個(gè)比第一種用法多了一個(gè)elementSelector,第一種用法是對(duì)集合本身按照TKey分組,并將自己(TSource)添加到分組內(nèi),而當(dāng)前的用法則可以選擇自己想要添加到分組內(nèi)的元素類型。
編寫客戶端實(shí)驗(yàn)代碼如下:
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進(jìn)行分組,并將p.Name作為組內(nèi)的元素。
輸出結(jié)果如下:
其等價(jià)的LINQ語(yǔ)句為:
var groups = from p in personList group p.Name by p.Gender;
五、第四種用法:
public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IEnumerable<TSource>, TResult> resultSelector);
官方釋義:根據(jù)指定的鍵選擇器函數(shù)對(duì)序列中的元素進(jìn)行分組,并且從每個(gè)組及其鍵中創(chuàng)建結(jié)果值。
這個(gè)跟之前的用法都不同,之前的用法都是將結(jié)果進(jìn)行分組,并返回IGrouping<TKey,TSource>對(duì)象,而當(dāng)前用法則是返回自己定義的類型(TResult),在返回自己定義類型之前,將會(huì)傳入兩個(gè)參數(shù),一個(gè)是TKey,為分組時(shí)指定的對(duì)象,另外一個(gè)則是IEnumerable<TSource>,為分組后的內(nèi)部對(duì)象集合。
編寫客戶端實(shí)驗(yàn)代碼如下:
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及以上。
以上代碼將分組后的內(nèi)容(一個(gè)是TKey,為p.Gender,另外一個(gè)是IEnumerable<TSource>,為IEnumerable<Person>)作為字符串輸出,因此,將返回的類型為字符串集合。
輸出結(jié)果如下:
其等價(jià)的LINQ語(yǔ)句為:
var results = from p in personList group p by p.Gender into pGroup select GetPersonInfo(pGroup.Key, pGroup);
六、第五種用法:
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);
官方釋義:根據(jù)鍵選擇器函數(shù)對(duì)序列中的元素進(jìn)行分組。通過使用比較器對(duì)鍵進(jìn)行比較,并且通過使用指定的函數(shù)對(duì)每個(gè)組的元素進(jìn)行投影。
與第三種用法基本相同,只是多了一個(gè)相等比較器,用于分組的依據(jù)。
使用第二種用法的personList及PersonEqualityComparer,編寫客戶端實(shí)驗(yàn)代碼如下:
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}"); } }
以上代碼的分組依據(jù)是Person,PersonEqualityComparer則是作為Person分組的比較器,每個(gè)組內(nèi)為一個(gè)匿名類型集合。
輸出結(jié)果如下:
七、第六種用法:
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);
官方釋義:根據(jù)指定的鍵選擇器函數(shù)對(duì)序列中的元素進(jìn)行分組,并且從每個(gè)組及其鍵中創(chuàng)建結(jié)果值。通過使用指定的比較器對(duì)鍵進(jìn)行比較。
與第四種用法基本相同,只是多了一個(gè)相等比較器,用于分組的依據(jù)。
使用第二種用法的personList及PersonEqualityComparer,編寫客戶端實(shí)驗(yàn)代碼如下:
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); }
以上代碼的分組依據(jù)是Person,PersonEqualityComparer則是作為Person分組的比較器,每個(gè)組內(nèi)為一個(gè)Person集合,并將返回類型為string的字符串輸出。
輸出結(jié)果如下:
八、第七種用法:
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);
官方釋義:根據(jù)指定的鍵選擇器函數(shù)對(duì)序列中的元素進(jìn)行分組,并且從每個(gè)組及其鍵中創(chuàng)建結(jié)果值。通過使用指定的函數(shù)對(duì)每個(gè)組的元素進(jìn)行投影。
與第四種方法很類似,只是對(duì)分組內(nèi)的元素進(jìn)行選擇,原有為TSource,現(xiàn)改為TElement。
編寫客戶端實(shí)驗(yàn)代碼如下:
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分組,并將分組后的信息組合成一條字符串,并輸出到控制臺(tái)。
輸出結(jié)果如下:
九、第八種用法:
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);
官方釋義: 根據(jù)指定的鍵選擇器函數(shù)對(duì)序列中的元素進(jìn)行分組,并且從每個(gè)組及其鍵中創(chuàng)建結(jié)果值。通過使用指定的比較器對(duì)鍵值進(jìn)行比較,并且通過使用指定的函數(shù)對(duì)每個(gè)組的元素進(jìn)行投影。
與第七種用法基本相同,只是多了一個(gè)相等比較器,用于分組的依據(jù)。
使用第二種用法的personList及PersonEqualityComparer,編寫客戶端實(shí)驗(yàn)代碼如下:
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比較器作為分組的依據(jù),并將分組后的信息組合成一條字符串,并輸出到控制臺(tái)。
輸出結(jié)果如下:
以上就是C#在LINQ中使用GroupBy的詳細(xì)內(nèi)容,更多關(guān)于C#使用GroupBy的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
VS2019 找不到資產(chǎn)文件 “xxxx\obj\project.assets.json”運(yùn)行NuGet包還原以生成此文
這篇文章主要介紹了VS2019 找不到資產(chǎn)文件 “xxxx\obj\project.assets.json”運(yùn)行NuGet包還原以生成此文件,本文給大家分享解決方案,感興趣的朋友跟隨小編一起學(xué)習(xí)吧2020-08-08DevExpress實(shí)現(xiàn)GridControl列頭繪制Checkbox的方法
這篇文章主要介紹了DevExpress實(shí)現(xiàn)GridControl列頭繪制Checkbox的方法,需要的朋友可以參考下2014-08-08C#中l(wèi)abel內(nèi)容顯示不全、不完整的解決方法
這篇文章主要介紹了C#中l(wèi)abel內(nèi)容顯示不全、不完整的解決方法,只需要把兩個(gè)屬性設(shè)置一下即可解決這個(gè)問題,需要的朋友可以參考下2015-06-06C#實(shí)現(xiàn)獲取程序路徑方法小結(jié)
這篇文章主要介紹了C#實(shí)現(xiàn)獲取程序路徑方法,實(shí)例分析了C#獲取文件路徑的各種常用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-08-08c#中將uint值轉(zhuǎn)換成int的實(shí)例方法
在本文里小編給大家整理的是關(guān)于c#中將uint值轉(zhuǎn)換成int的實(shí)例方法,需要的朋友們學(xué)習(xí)參考下。2019-08-08超簡(jiǎn)單C#獲取帶漢字的字符串真實(shí)長(zhǎng)度(單個(gè)英文長(zhǎng)度為1,單個(gè)中文長(zhǎng)度為2)
正常情況下,我們是直接去string的length的,但是漢字是有兩個(gè)字節(jié)的,所以直接用length是錯(cuò)的2018-03-03