Linq常用方法汇总

Linq常用方法汇总

先构造几个集合,方便后面使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
List<string> names = new List<string> { "Alice", "Bob", "Charlie", "David", "Eve" };

var people = new List<Person>
{
new Person { Name = "Alice", Age = 30, City = "Beijing" },
new Person { Name = "Bob", Age = 25, City = "Shanghai" },
new Person { Name = "Charlie", Age = 35, City = "Beijing" },
new Person { Name = "David", Age = 28, City = "Guangzhou" },
new Person { Name = "Eve", Age = 22, City = "Shanghai" },
};

class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string City { get; set; }
}

筛选

Where过滤序列,返回满足条件的所有元素


Where(Func<TSource, bool> predicate)

Where(Func<TSource, int, bool> predicate) — 第二个参数是元素的索引


1
2
// 年龄 >= 30 的人
var age30Plus = people.Where(p => p.Age >= 30);

image-20251201103654726

1
2
// 使用索引:选出索引为偶数的位置上的名字
var evenIndexNames = names.Where((name, idx) => idx ==2);

image-20251201103713455

投影

Select

作用:把序列的每个元素映射成新形式(投影)。
常见重载

  • Select(Func<TSource, TResult> selector)
  • Select(Func<TSource, int, TResult> selector) — 可使用元素索引

1
2
// 只投影名字和城市(匿名类型)
var nameAndCity = people.Select(p => new { p.Name, p.City });

image-20251201103943581

1
2
// 使用索引:给名字附加序号
var numberedNames = names.Select((n, i) => $"{i + 1}. {n}");

image-20251201104010923

SelectMany

作用:把每个元素映射到一个序列,然后将所有子序列“扁平化”为一个序列(常用于一对多关系)。
常见重载

  • SelectMany(Func<TSource, IEnumerable<TResult>> selector)
  • SelectMany(Func<TSource, int, IEnumerable<TResult>> selector)(带索引)
  • SelectMany(selector, resultSelector) — 可以在扁平化的同时生成复合结果

和Select的区别

SelectSelectMany
我给你每个元素转换一下(不会打散内部集合)我给你每个元素转换一下,顺便把内部集合展开成一个大列表
1
2
3
4
5
6
7
8
9
10
11
12
//先构建个数据,每个人对应一个数组,可以居住多个城市
class Person
{
public string Name { get; set; }
public List<string> Cities { get; set; }
}
var people = new List<Person>
{
new Person { Name = "Alice", Cities = new List<string> { "Beijing", "Shanghai" }},
new Person { Name = "Bob", Cities = new List<string> { "Guangzhou" }},
new Person { Name = "Charlie", Cities = new List<string> { "Beijing", "Shenzhen", "Hangzhou" }}
};
  • Select

people.Select(p =>p.Cities );

image-20251201104803756

  • SelectMany

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

image-20251201104813867

还可以用带结果选择器的高级用法,先把每个外层元素映射到一个子序列,然后把所有子序列“扁平化”成一个一维序列。当你需要在“展开”的同时把外层元素和内层元素组合成新的结果时,就用 带结果选择器(result selector) 的重载。

people.SelectMany(p => p.Cities, (person, city) => new {person.Name,city});这个案例,不仅有城市序列,还有对应的Name序列。

image-20251201105615717

排序

  1. OrderBy升序

people.OrderBy(p => p.Age)

image-20251201110144671

  1. OrderByDescending降序

people.OrderByDescending(p => p.Name)

image-20251201110218761

  1. ThenBy / ThenByDescending 在主排序的基础上做次级排序(用于多键排序)
1
2
// 先按城市排序,再按年龄降序
var cityThenAge = people.OrderBy(p => p.City).ThenByDescending(p => p.Age)

image-20251201110350593

分组

GroupBy

作用:按照键把序列分成多个组,每组是 IGrouping<TKey, TElement>
常见重载

  • GroupBy(Func<TSource, TKey> keySelector)
  • GroupBy(keySelector, elementSelector)(将元素投影成其他类型)
  • GroupBy(keySelector, elementSelector, resultSelector)(可以直接构造自定义结果)
  • 可带 IEqualityComparer<TKey>
1
2
// 按城市分组
var byCity = people.GroupBy(p => p.City).Dump();

image-20251201110558653

1
2
3
4
5
6
// 如果只想统计每个城市的人名列表
var cityToNames = people.GroupBy(
p => p.City,
p => p.Name, // elementSelector:组内只保留名字
(city, namesInCity) => new { City = city, Names = namesInCity.ToList() } // resultSelector
);

image-20251201111816519

集合操作

Distinct返回序列中不重复的元素

1
2
var numsWithDup = new List<int> { 1, 2, 2, 3, 3, 3 };
var distinctNums = numsWithDup.Distinct().Dump();

image-20251201112004216

Union返回两个序列的并集(去重)

1
2
3
var a = new List<int> { 1, 2, 3 };
var b = new List<int> { 3, 4, 5 };
var union = a.Union(b).Dump(); // 1,2,3,4,5

image-20251201112045356

Intersect返回两个序列的交集(共有元素)

1
var intersect = a.Intersect(b).Dump(); // 3

image-20251201112139690

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

image-20251201112223401

分区

Skip跳过前 n 个元素

1
var skip2 = numbers.Skip(2).Dump(); // 3,4,5,6

image-20251201112419467

Take 取前 n 个元素

1
var first3 = numbers.Take(3).Dump(); // 1,2,3

image-20251201112432287

SkipWhile根据条件从序列开头开始判断,直到条件不再满足为止,序列开头跳过元素,一旦 predicate 返回 false 则后续元素都保留。

1
var skipWhileLess4 = numbers.SkipWhile(n => n < 4).Dump(); // 4,5,6

image-20251201112628486

TakeWhile根据条件从序列开头开始判断,直到条件不再满足为止,从序列开头取元素,一旦 predicate 返回 false 则停止(剩余元素丢弃)

1
var takeWhileLess4 = numbers.TakeWhile(n => n < 4).Dump(); // 1,2,3

image-20251201112648764

量词

Any判断序列中是否存在至少一个满足条件的元素

1
2
bool anyAdults = people.Any(p => p.Age >= 18).Dump(); 
bool hasElements = numbers.Any().Dump(); //判断序列是否为空

All判断序列中的所有元素是否都满足条件

1
bool allAbove20 = people.All(p => p.Age > 20).Dump();

注意:空序列对 All 返回 true(逻辑上所有元素都满足)。

1
2
var ll = new List<Person>();
bool allAbove20 = ll.All(p=>p.Age>20).Dump(); //true

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
2
int sumNums = numbers.Sum();
int totalAge = people.Sum(p => p.Age);

Max / Min获取序列的最大/最小值,或按投影选择最大/最小。

1
2
3
int maxNum = numbers.Max();
int oldest = people.Max(p => p.Age);
string maxName = names.Max(); // 字符串按字典序

Average计算平均值(适用于数值序列)

1
2
double avgAge = people.Average(p => p.Age);
double avgNum = numbers.Average();

Aggregate对集合元素进行累积/折叠运算,可以自定义累加逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//1累加求和
int sum = numbers.Aggregate((acc, x) => acc + x);
//带初始值求和(安全处理空集合)
int sum2 = numbers.Aggregate(0, (acc, x) => acc + x);
//拼接字符串
names.Aggregate((acc, word) => acc + "-" + word);//Alice-Bob-Charlie-David-Eve
//生成字典(统计字母长度)
var lengthDict = words.Aggregate(
new Dictionary<string, int>(),
(dict, word) =>
{
dict[word] = word.Length;
return dict;
}
);

image-20251201134105051

1
2
//初始值 + 最终投影(转换类型)
numbers.Aggregate("总数:",(acc,x)=>acc+" "+x,ac=>ac+"结束"); //总数: 1 2 3 4 5 6结束

转换

ToList / ToArrayIEnumerable<T> 枚举序列转换为 List<T>T[],触发延迟执行并把结果缓存到集合中。

1
2
var list = people.Where(p => p.Age > 25).ToList();
var arr = names.Where(n => n.StartsWith("A")).ToArray();

ToDictionary将序列转换为字典

1
var dictByName = people.ToDictionary(p => p.Name);

image-20251201115004801

1
2
// 以 City 为键,保存该城市第一个人的年龄(注意键冲突需谨慎)
var cityToFirstAge = people.ToDictionary(p => p.Name, p => p.Age).Dump();

image-20251201115037665

OfType过滤并转换序列中可以转换为 TResult 的元素(安全地筛选类型)

1
2
3
IEnumerable<object> mixed = new object[] { 1, "two", 3, "four" };
var strings = mixed.OfType<string>().Dump(); // "two", "four"
var ints = mixed.OfType<int>().Dump(); // 1,3

image-20251201115154976

Cast尝试把所有元素强制转换为 TResult(如果某个元素无法转换会抛异常)。

1
var castToInt = mixed.Cast<int>().Dump(); // 会在遇到 "two" 时抛异常
作者

步步为营

发布于

2025-12-01

更新于

2025-12-01

许可协议