Linq 虽然用得多,但是里面有一些方法比较少用,因此整理一下。Enumerable 类的所有方法可以在 MSDN 上查阅到:https://msdn.microsoft.com/zh-cn/library/system.linq.enumerable.aspx
Aggregate
这个方法有三个重载,先看第一个
Aggregate(IEnumerable, Func)
参数是接受两个 TSource 类型的输入,返回一个 TSource 类型的输出。
按照 MSDN 上的说明,输入的第一个参数是累加的值,第二个参数是元素。
{ int[] array = new[] { 1, 2, 3, 4, 5 }; int result = array.Aggregate((sum, i) => sum + i); Console.WriteLine(result); } { string[] array = new string[] { "hello", "world", "!" }; string result = array.Aggregate((combine, str) => { return combine + " " + str; }); Console.WriteLine(result); }
则会输出 15 和 hello world !
在第一次进入 Aggregate 的 Func 时,combine 的值为第一个元素的值,str 为第二个元素的值。
当输入的序列的元素个数为 0 时,则抛出 InvalidOperationException 异常。
而当元素的个数只有一个的时候,则不会执行 Func。
接下来看第二个重载
Aggregate(IEnumerable, TAccumulate, Func)
比起第一个重载,多了一个参数输入参数 TAccumulate,泛型参数也变成了两个。
{ int[] array = new[] { 1, 2, 3, 4, 5 }; long result = array.Aggregate(-1L, (sum, i) => { return sum + i; }); Console.WriteLine(result); }
那么这段代码的输出则会是 14。第一次进入 Func 的时候,sum 的值为 -1L,i 的值是 1,这个行为跟第一个重载稍微有点区别。
而且当元素只有一个的时候,也是会进入 Func 的
当序列为空的时候,也不会触发到异常
直接等于输入参数的值。
第三个重载
Aggregate(IEnumerable, TAccumulate, Func, Func)
这个其实就是相当与第二个重载增加了最后一个参数
{ string[] array = new string[] { "hello", "world", "!" }; string result = array.Aggregate("start", (combine, str) => { return combine + " " + str; }, end => end.ToUpperInvariant()); Console.WriteLine(result); }
执行后会输出 START HELLO WORLD !。
最后的那个参数相对于对最终结果进行了一下处理,跟下面的代码是等价的。
{ string[] array = new string[] { "hello", "world", "!" }; string result = array.Aggregate("start", (combine, str) => { return combine + " " + str; }).ToUpperInvariant(); Console.WriteLine(result); }
DefaultIfEmpty
第一个重载
DefaultIfEmpty(IEnumerable)
就是说,如果一个序列的元素个数是零个的话,那就返回一个只有一个 default(TSource) 元素的序列。感觉这没啥用(lll¬ω¬)
看另一个重载
DefaultIfEmpty(IEnumerable, TSource)
多了个参数,猜也猜得出来了
唔,好像还是没啥实用意义…………
Except
Except(IEnumerable, IEnumerable)
求差集
A 序列减去 B 序列,并且去重了。
另一重载
Except(IEnumerable, IEnumerable, IEqualityComparer)
多了一个比较器
最后只会输出 Hello,因为在 IgnoreCase 比较器下,world 和 WORLD 是一样的。
GroupBy
虽然用得还是比较多,但是重载比较多,还是写一下吧。
GroupBy(IEnumerable, Func)
这个是最简单的重载了。
根据 Age 分组,这个重载很简单,也是最常用的。
GroupBy(IEnumerable, Func, IEqualityComparer)
多了一个比较器,不难
Key 会根据第一次匹配到的值。
GroupBy(IEnumerable, Func, Func)
第一个重载的改版而且,如果将上面的 person => person.Name 改为 person => person,那跟第一个重载没区别。
GroupBy(IEnumerable, Func, Func, IEqualityComparer)
多了一个比较器而已,不说了。
GroupBy(IEnumerable, Func, Func, TResult>)
分完组后对每一组进行了一下处理。
GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer)
比上面多了一个比较器,不说了。
GroupBy(IEnumerable, Func, Func, Func, TResult>)
多了元素选择的参数重载,参考上面。
GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer)
多了选择器,不说。
Join
Join(IEnumerable, IEnumerable, Func, Func, Func)
这个其实不难,只要参考一下 SQL 中的 inner join 的话。
先初始化测试数据
Listlist1 = new List () { new Person() { Id = 1, Gender = "M" }, new Person() { Id = 2 , Gender = "F" }, new Person() { Id = 3, Gender = "M" } }; List list2 = new List () { new Student() { Id = 1, Name = "martin" }, new Student() { Id = 2, Name = "valid void" }, new Student() { Id = 4, Name = "justin" } };
然后测试代码走起
没啥难的,等价于以下的 linq 写法
Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer)
多了个比较器,用于比较 key,不说了。
GroupJoin
GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>)
看上去很复杂,但其实可以参考 Join 的输入进行对比。
测试数据我们还是沿用 Join 的。执行测试代码
对等的 linq 写法如下
var result = (from person in list1 join student in list2 on person.Id equals student.Id into studentGroup select new { Id = person.Id, Gender = person.Gender, Students = studentGroup.ToList() }).ToList();
GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer)
多了一个比较器,不说了。
SelectMany
这个最近这段时间用得比较多,也记录一下吧
SelectMany(IEnumerable, Func>)
测试代码
简单的来说就是将一个 IEnumerable
对等的 linq 写法
感觉 linq 写法会相对比较好理解的说。
SelectMany(IEnumerable, Func>)
Func 多了个 Int32 的参数,看测试代码
很好理解,就是当前的索引。
SelectMany(IEnumerable, Func>, Func)
比起第一个就是多了个结果执行而已
会进入这个 Func 四次,前两次是 helloword 那个 List,后两次是 justin martin 那个 List。
SelectMany(IEnumerable, Func>, Func)
多了索引,参考上面。
SequenceEqual
序列比较,知道有这个东西,但平时好像没有怎么用过。
SequenceEqual(IEnumerable, IEnumerable)
很好理解,首要前提肯定是元素个数相等,其次要每一个元素相等。
SequenceEqual(IEnumerable, IEnumerable, IEqualityComparer)
多了个比较器,不说了。
SkipWhile
Skip 倒是一直在用,SkipWhile 就用得比较少,也记录一下吧。
SkipWhile(IEnumerable, Func)
不难,就是当 Func 返回 false 时停止。
因为当去到 3 的时候为 false,因此返回 3 和剩下的元素。
SkipWhile(IEnumerable, Func)
多了个索引而已,没啥好说的。
ToDictionary
先看第一个重载
ToDictionary(IEnumerable, Func)
不难,Func 就是获取按照什么来生成 Key。
另外使用这个方法是要注意,Key 是不能重复的。
所以说实话,这方法平时比较少用。。。
ToDictionary(IEnumerable, Func, IEqualityComparer)
多了一个比较器,没啥好说的。
ToDictionary(IEnumerable, Func, Func)
比起第一个重载,多了一个如何生成字典的值的 Func,也没啥好说的。
ToDictionary(IEnumerable, Func, Func, IEqualityComparer)
多了比较器,不说了。
ToLookup
这个有点像上面的 ToDictionary 的。
ToLookup(IEnumerable, Func)
跟 ToDictionary 的第一个重载的输入参数是一样的。
ILookup
当元素的 Key 重复的时候:
那么这个 lookup 就只有一个 group 了,但这个 group 就会有多个元素。
ToLookup(IEnumerable, Func, IEqualityComparer)
ToLookup(IEnumerable, Func, Func)
ToLookup(IEnumerable, Func, Func, IEqualityComparer)
这三个重载可以参考一下 ToDictionary 的重载,一样的说。
Zip
这个方法就只有一个,没别的重载
Zip(IEnumerable, IEnumerable, Func)
这里就借用 MSDN 上的示例代码了,看结果也看得出 Zip 这个操作的逻辑了。遍历两个序列进行操作,直到其中一个到达尾部。
另外像 TakeWhile 可以参考上面的 SkipWhile 就不说了。Distinct、Union 和 Intersect 平时也用得比较多,因此也不说了。