先構造幾個集合,方便後面使用

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) — 第二個參數是元素的索引


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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_Max

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_ci_02

投影

Select

作用:把序列的每個元素映射成新形式(投影)。 常見重載

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

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_Max_03

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_List_04

SelectMany

作用:把每個元素映射到一個序列,然後將所有子序列“扁平化”為一個序列(常用於一對多關係)。 常見重載

  • SelectMany(Func<TSource, IEnumerable<TResult>> selector)
  • SelectMany(Func<TSource, int, IEnumerable<TResult>> selector)(帶索引)
  • SelectMany(selector, resultSelector) — 可以在扁平化的同時生成複合結果

和Select的區別

Select

SelectMany

我給你每個元素轉換一下(不會打散內部集合)

我給你每個元素轉換一下,順便把內部集合展開成一個大列表

//先構建個數據,每個人對應一個數組,可以居住多個城市
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 );

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_Max_05

  • SelectMany

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_List_06

還可以用帶結果選擇器的高級用法,先把每個外層元素映射到一個子序列,然後把所有子序列“扁平化”成一個一維序列。當你需要在“展開”的同時把外層元素和內層元素組合成新的結果時,就用 帶結果選擇器(result selector) 的重載。

people.SelectMany(p => p.Cities, (person, city) => new {person.Name,city});這個案例,不僅有城市序列,還有對應的Name序列。

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_List_07

排序

  1. OrderBy升序

people.OrderBy(p => p.Age)

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_ci_08

  1. OrderByDescending降序

people.OrderByDescending(p => p.Name)

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_Max_09

  1. ThenBy / ThenByDescending 在主排序的基礎上做次級排序(用於多鍵排序)
// 先按城市排序,再按年齡降序
var cityThenAge = people.OrderBy(p => p.City).ThenByDescending(p => p.Age)

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_List_10

分組

GroupBy

作用:按照鍵把序列分成多個組,每組是 IGrouping<TKey, TElement>。 常見重載

  • GroupBy(Func<TSource, TKey> keySelector)
  • GroupBy(keySelector, elementSelector)(將元素投影成其他類型)
  • GroupBy(keySelector, elementSelector, resultSelector)(可以直接構造自定義結果)
  • 可帶 IEqualityComparer<TKey>
// 按城市分組
var byCity = people.GroupBy(p => p.City).Dump();

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_List_11

// 如果只想統計每個城市的人名列表
var cityToNames = people.GroupBy(
    p => p.City,
    p => p.Name, // elementSelector:組內只保留名字
    (city, namesInCity) => new { City = city, Names = namesInCity.ToList() } // resultSelector
);

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_List_12

集合操作

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

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_List_13

Union返回兩個序列的並集(去重)

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_Max_14

Intersect返回兩個序列的交集(共有元素)

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_Max_15

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_Max_16

分區

Skip跳過前 n 個元素

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_ci_17

Take 取前 n 個元素

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_List_18

SkipWhile根據條件從序列開頭開始判斷,直到條件不再滿足為止,序列開頭跳過元素,一旦 predicate 返回 false 則後續元素都保留。

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_ci_19

TakeWhile根據條件從序列開頭開始判斷,直到條件不再滿足為止,從序列開頭取元素,一旦 predicate 返回 false 則停止(剩餘元素丟棄)

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_ci_20

量詞

Any判斷序列中是否存在至少一個滿足條件的元素

bool anyAdults = people.Any(p => p.Age >= 18).Dump(); 
bool hasElements = numbers.Any().Dump(); //判斷序列是否為空

All判斷序列中的所有元素是否都滿足條件

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

注意:空序列對 All 返回 true(邏輯上所有元素都滿足)。

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

Contains 判斷序列是否包含某個具體值

bool hasThree = numbers.Contains(3);

元素操作

First

作用:返回序列中的第一個元素或第一個滿足條件的元素。

  • First():如果找不到元素會拋出 InvalidOperationException
  • FirstOrDefault():找不到則返回類型默認值(引用類型為 null,值類型為 default(T))。

FirstOrDefault

Last / LastOrDefault,與 First 類似,但返回序列中的最後一個元素(或滿足條件的最後一個)

Single / SingleOrDefault

作用:要求序列恰好包含一個元素(或恰好有一個滿足條件的元素)。

  • Single():如果序列為空或包含多個元素會拋異常。
  • SingleOrDefault():如果序列為空返回默認值;如果包含多個元素仍會拋異常。

聚合

Count返回序列元素數量。可帶謂詞計算滿足條件的數量。

int beijingCount = people.Count(p => p.City == "Beijing")

Sum對數值序列求和,或投影后求和

int sumNums = numbers.Sum();
int totalAge = people.Sum(p => p.Age);

Max / Min獲取序列的最大/最小值,或按投影選擇最大/最小。

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

Average計算平均值(適用於數值序列)

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

Aggregate對集合元素進行累積/摺疊運算,可以自定義累加邏輯

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_Max_21

//初始值 + 最終投影(轉換類型)
numbers.Aggregate("總數:",(acc,x)=>acc+" "+x,ac=>ac+"結束"); //總數: 1 2 3 4 5 6結束

轉換

ToList / ToArray將 IEnumerable<T> 枚舉序列轉換為 List<T> 或 T[],觸發延遲執行並把結果緩存到集合中。

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

ToDictionary將序列轉換為字典

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_List_22

// 以 City 為鍵,保存該城市第一個人的年齡(注意鍵衝突需謹慎)
var cityToFirstAge = people.ToDictionary(p => p.Name, p => p.Age).Dump();

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_Max_23

OfType過濾並轉換序列中可以轉換為 TResult 的元素(安全地篩選類型)

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

C#中Linq常用方法彙總,一篇能覆蓋99%使用場景_ci_24

Cast嘗試把所有元素強制轉換為 TResult(如果某個元素無法轉換會拋異常)。

var castToInt = mixed.Cast<int>().Dump(); // 會在遇到 "two" 時拋異常