Linq常用方法汇总
先构造几个集合,方便后面使用
1 | List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 }; |
筛选
Where过滤序列,返回满足条件的所有元素
Where(Func<TSource, bool> predicate)
Where(Func<TSource, int, bool> predicate) — 第二个参数是元素的索引
1 | // 年龄 >= 30 的人 |

1 | // 使用索引:选出索引为偶数的位置上的名字 |

投影
Select
作用:把序列的每个元素映射成新形式(投影)。
常见重载:
Select(Func<TSource, TResult> selector)Select(Func<TSource, int, TResult> selector)— 可使用元素索引
1 | // 只投影名字和城市(匿名类型) |

1 | // 使用索引:给名字附加序号 |

SelectMany
作用:把每个元素映射到一个序列,然后将所有子序列“扁平化”为一个序列(常用于一对多关系)。
常见重载:
SelectMany(Func<TSource, IEnumerable<TResult>> selector)SelectMany(Func<TSource, int, IEnumerable<TResult>> selector)(带索引)SelectMany(selector, resultSelector)— 可以在扁平化的同时生成复合结果
和Select的区别
| Select | SelectMany |
|---|---|
| 我给你每个元素转换一下(不会打散内部集合) | 我给你每个元素转换一下,顺便把内部集合展开成一个大列表 |
1 | //先构建个数据,每个人对应一个数组,可以居住多个城市 |
- Select
people.Select(p =>p.Cities );

- SelectMany
people.SelectMany(p => p.Cities );

还可以用带结果选择器的高级用法,先把每个外层元素映射到一个子序列,然后把所有子序列“扁平化”成一个一维序列。当你需要在“展开”的同时把外层元素和内层元素组合成新的结果时,就用 带结果选择器(result selector) 的重载。
people.SelectMany(p => p.Cities, (person, city) => new {person.Name,city});这个案例,不仅有城市序列,还有对应的Name序列。

排序
OrderBy升序
people.OrderBy(p => p.Age)

OrderByDescending降序
people.OrderByDescending(p => p.Name)

ThenBy / ThenByDescending在主排序的基础上做次级排序(用于多键排序)
1 | // 先按城市排序,再按年龄降序 |

分组
GroupBy
作用:按照键把序列分成多个组,每组是 IGrouping<TKey, TElement>。
常见重载:
GroupBy(Func<TSource, TKey> keySelector)GroupBy(keySelector, elementSelector)(将元素投影成其他类型)GroupBy(keySelector, elementSelector, resultSelector)(可以直接构造自定义结果)- 可带
IEqualityComparer<TKey>
1 | // 按城市分组 |

1 | // 如果只想统计每个城市的人名列表 |

集合操作
Distinct返回序列中不重复的元素
1 | var numsWithDup = new List<int> { 1, 2, 2, 3, 3, 3 }; |

Union返回两个序列的并集(去重)
1 | var a = new List<int> { 1, 2, 3 }; |

Intersect返回两个序列的交集(共有元素)
1 | var intersect = a.Intersect(b).Dump(); // 3 |

Except返回第一个序列中存在但第二个序列中不存在的元素(差集)

分区
Skip跳过前 n 个元素
1 | var skip2 = numbers.Skip(2).Dump(); // 3,4,5,6 |

Take 取前 n 个元素
1 | var first3 = numbers.Take(3).Dump(); // 1,2,3 |

SkipWhile根据条件从序列开头开始判断,直到条件不再满足为止,序列开头跳过元素,一旦 predicate 返回 false 则后续元素都保留。
1 | var skipWhileLess4 = numbers.SkipWhile(n => n < 4).Dump(); // 4,5,6 |

TakeWhile根据条件从序列开头开始判断,直到条件不再满足为止,从序列开头取元素,一旦 predicate 返回 false 则停止(剩余元素丢弃)
1 | var takeWhileLess4 = numbers.TakeWhile(n => n < 4).Dump(); // 1,2,3 |

量词
Any判断序列中是否存在至少一个满足条件的元素
1 | bool anyAdults = people.Any(p => p.Age >= 18).Dump(); |
All判断序列中的所有元素是否都满足条件
1 | bool allAbove20 = people.All(p => p.Age > 20).Dump(); |
注意:空序列对 All 返回 true(逻辑上所有元素都满足)。
1 | var ll = new List<Person>(); |
Contains判断序列是否包含某个具体值
1 | bool hasThree = numbers.Contains(3); |
元素操作
First
作用:返回序列中的第一个元素或第一个满足条件的元素。
First():如果找不到元素会抛出InvalidOperationException。FirstOrDefault():找不到则返回类型默认值(引用类型为null,值类型为default(T))。
FirstOrDefault
Last / LastOrDefault,与 First 类似,但返回序列中的最后一个元素(或满足条件的最后一个)
Single / SingleOrDefault
作用:要求序列恰好包含一个元素(或恰好有一个满足条件的元素)。
Single():如果序列为空或包含多个元素会抛异常。SingleOrDefault():如果序列为空返回默认值;如果包含多个元素仍会抛异常。
聚合
Count返回序列元素数量。可带谓词计算满足条件的数量。
1 | int beijingCount = people.Count(p => p.City == "Beijing") |
Sum对数值序列求和,或投影后求和
1 | int sumNums = numbers.Sum(); |
Max / Min获取序列的最大/最小值,或按投影选择最大/最小。
1 | int maxNum = numbers.Max(); |
Average计算平均值(适用于数值序列)
1 | double avgAge = people.Average(p => p.Age); |
Aggregate对集合元素进行累积/折叠运算,可以自定义累加逻辑
1 | //1累加求和 |

1 | //初始值 + 最终投影(转换类型) |
转换
ToList / ToArray将 IEnumerable<T> 枚举序列转换为 List<T> 或 T[],触发延迟执行并把结果缓存到集合中。
1 | var list = people.Where(p => p.Age > 25).ToList(); |
ToDictionary将序列转换为字典
1 | var dictByName = people.ToDictionary(p => p.Name); |

1 | // 以 City 为键,保存该城市第一个人的年龄(注意键冲突需谨慎) |

OfType过滤并转换序列中可以转换为 TResult 的元素(安全地筛选类型)
1 | IEnumerable<object> mixed = new object[] { 1, "two", 3, "four" }; |

Cast尝试把所有元素强制转换为 TResult(如果某个元素无法转换会抛异常)。
1 | var castToInt = mixed.Cast<int>().Dump(); // 会在遇到 "two" 时抛异常 |
Linq常用方法汇总

