声明:本文为www.cnc6.cn原创,转载时请注明出处,谢谢!

本文作者文采欠佳,文字表达等方面不是很好,但实际的代码例子是非常实用的,请作参考。

一、先准备要使用的类:

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、准备要使用的List,用于分组(GroupBy):

        List<Person> personList = new List<Person>
{
new Person
{
Name = "P1", Age = , Gender = "Male" },
new Person
{
Name = "P2", Age = , Gender = "Male",
},
new Person
{
Name = "P2", Age = ,Gender = "Female",
}
};

二、第一种用法:

public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);

官方释义:根据指定的键选择器函数对序列中的元素进行分组。

我们要分组的集合为source,集合内每个元素的类型为TSource,这里第一个参数keySelector的类型为Func<TSource, TKey>,用于将TSource元素按照由此委托返回的类型TKey进行分组,结果为一个已分好组的集合(集合中的集合)。

编写客户端试验代码如下:

        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循环将分组的内容打印到控制台。

因为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,并将分组的结果选择出来合并成一个集合。

三、第二种用法:

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 = , Gender = "Male" },
new Person
{
Name = "P1", Age = , Gender = "Male",
},
new Person
{
Name = "P3", Age = ,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相同,就分为一组,

输出结果如下:

四、第三种用法:

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;

五、第四种用法:

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);

六、第五种用法:

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分组的比较器,每个组内为一个匿名类型集合。

输出结果如下:

七、第六种用法:

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的字符串输出。

输出结果如下:

八、第七种用法:

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分组,并将分组后的信息组合成一条字符串,并输出到控制台。

输出结果如下:

九、第八种用法:

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比较器作为分组的依据,并将分组后的信息组合成一条字符串,并输出到控制台。

输出结果如下:

LINQ 之 GroupBy的更多相关文章

  1. Linq Mysql GroupBy语句的问题处理

    语句如下: var resumeList = db.ChannelResume.Where(model); var groupValues = resumeList.GroupBy(t => n ...

  2. linq lambda GroupBy 用法

    Linq 中按照多个值进行分组(GroupBy)   /// <summary>要查询的对象</summary> class Employee { public int ID ...

  3. 转载有个小孩跟我说LINQ(重点讲述Linq中GroupBy的原理及用法)

    转载原出处: http://www.cnblogs.com/AaronYang/archive/2013/04/02/2994635.html 小孩LINQ系列导航:(一)(二)(三)(四)(五)(六 ...

  4. 转载Linq中GroupBy方法的使用总结

    Group在SQL经常使用,通常是对一个字段或者多个字段分组,求其总和,均值等. Linq中的Groupby方法也有这种功能.具体实现看代码: 假设有如下的一个数据集: public class St ...

  5. [C#] LINQ之GroupBy

    声明:本文为www.cnc6.cn原创,转载时请注明出处,谢谢! 本文作者文采欠佳,文字表达等方面不是很好,但实际的代码例子是非常实用的,请作参考. 一.先准备要使用的类: 1.Person类: cl ...

  6. Linq中GroupBy方法的使用总结(转)

    Group在SQL经常使用,通常是对一个字段或者多个字段分组,求其总和,均值等. Linq中的Groupby方法也有这种功能.具体实现看代码: 假设有如下的一个数据集: public class St ...

  7. Linq中GroupBy方法的使用总结(转载)

    from:https://www.cnblogs.com/zhouzangood/articles/4565466.html Group在SQL经常使用,通常是对一个字段或者多个字段分组,求其总和,均 ...

  8. c# linq 分组groupby

    转载: https://www.cnblogs.com/cncc/p/9846390.html 一.先准备要使用的类: 1.Person类: class Person { public string ...

  9. DataTable/Array Linq查询,groupby

    DataTable Linq查询 1.查询DataRow IEnumerable<DataRow> q1 = from r in dt.AsEnumerable() == select r ...

随机推荐

  1. Daily Life 01

    2019-03-03 我不擅于用文字记录自己的生活,因为很长时间一个人习惯了随意简单的生活,觉得很多事留给回忆就好,另一方面文笔不好,怕自己流出的文字不有趣,过于流水.有看过一些身边人写的随记,都有写 ...

  2. JVM之垃圾收集器

    前一篇讲了垃圾收集算法--JVM之GC算法.垃圾收集算法——标记-清除算法.复制算法.标记-整理算法.分代收集算法,如果把它看作是方法论,那么下面说的就应该是内存回收的具体实现. 先看一下JVM中有哪 ...

  3. Java中String做为synchronized同步锁使用详解

    Java中使用String作同步锁 在Java中String是一种特殊的类型存在,在jdk中String在创建后是共享常量池的,即使在jdk1.8之后实现有所不同,但是功能还是差不多的. 借助这个特点 ...

  4. 测试 ASP.NET Core API Controller

    本文需要您了解ASP.NET Core MVC/Web API, xUnit以及Moq相关知识. 这里有xUnit和Moq的介绍: https://www.cnblogs.com/cgzl/p/917 ...

  5. 为什么要重写hashcode和equals方法?初级程序员在面试中很少能说清楚。

    我在面试 Java初级开发的时候,经常会问:你有没有重写过hashcode方法?不少候选人直接说没写过.我就想,或许真的没写过,于是就再通过一个问题确认:你在用HashMap的时候,键(Key)部分, ...

  6. 【Netty】(5)源码 Bootstrap

    [Netty]5 源码 Bootstrap 上一篇讲了AbstractBootstrap,为这篇做了个铺垫. 一.概述 Bootstrap 是 Netty 提供的一个便利的工厂类, 我们可以通过它来完 ...

  7. 我的2018OKR年终回顾与2019OKR初步规划

    转眼一年又过去了,在这个年底的时候,按照国际惯例,又到了重新回顾审视一下这一年来的得失,规划一下明年的奋斗方向的时候了.因此,我继续使用OKR来给自己做Review和Planning,也希望自己能够保 ...

  8. 在dotnet core下去中心化访问HTTP服务集群

    一般应用服务都会部署到多台服务器之上,一.可以通过硬件得到更多的并发处理能力:二.可以避免单点太故障的出现,从而确保服务7X24有效运作.当访问这些HTTP服务的情况一般都是经过反向代理服务进行统一处 ...

  9. @vue-cli3创建项目报错:ERROR command failed: npm install --loglevel error --registry=https://registry.npm.taobao.org --di

    使用@vue-cli3时 在你感觉所以配置都搞好开始创建项目时,不停的报错,就是创建不成功 清npm缓存也不行 改淘宝镜像也不行 就快奔溃了,最后最终(其实我在凑150字,为了能发到首页给更多采坑的兄 ...

  10. 使用IO流写文件的一些骚操作

    序言 当需要对文件进行操作时,使用IO流是不能避免的操作:比如业务中需要存储一些请求的响应结果中的一些内容.当所需处理的文件过大时,如果频繁的关闭文件流,会造成很大的开销,何时关闭?往往会造成比较大的 ...