常用語法,具體問題具體分析
- 1. Select
- 2. SelectMany
- 3. Where
- 4. Take
- 5. TakeWhile
- 6. SkipWhile
- 7. Join
- 8. GroupJoin
- 9. OrderBy
- 10. OrderByDescending
- 11. ThenBy
- 12. Concat
- 13. Zip
- 14. Distinct
- 15. Except
- 16. Union
- 17. Intersect
- 18. Concat
- 19. Reverse
- 20. SequenceEqual
- 21. ToLookup
- 22. OfType
- 23. Cast
- 24. Range
- 22. Repeat
- 25. Prepend
- 總結
1. Select
將集合中的每個元素投影(轉換)為另一種形式。
IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source,Func<TSource, TResult> selector
);
source
: 需要投影的源集合。selector
: 投影邏輯(Lambda表達式)。- 案例
var students = new List<Student>
{new Student { Id = 1, Name = "Alice", Age = 20 },new Student { Id = 2, Name = "Bob", Age = 22 }
};// 將學生對象投影為只包含姓名和年齡的匿名類型
var namesAndAges = students.Select(s => new { s.Name, s.Age });// 輸出:
// { Name = "Alice", Age = 20 }
// { Name = "Bob", Age = 22 }
2. SelectMany
將集合中的每個元素展開為多個元素,然后合并成一個單一的集合。
IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source,Func<TSource, IEnumerable<TResult>> selector
);
- 案例
var groups = new List<List<int>>
{new List<int> { 1, 2 },new List<int> { 3, 4 },new List<int> { 5, 6 }
};// 展開所有子列表為一個扁平列表
var flattened = groups.SelectMany(g => g);// 輸出:1, 2, 3, 4, 5, 6
3. Where
根據條件篩選集合中的元素,返回滿足條件的元素子集。
IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,Func<TSource, bool> predicate
);
source
: 需要篩選的源集合。predicate
: 篩選條件(Lambda表達式或委托)。- 案例
var students = new List<Student>
{new Student { Id = 1, Name = "Alice", Age = 20 },new Student { Id = 2, Name = "Bob", Age = 22 },new Student { Id = 3, Name = "Charlie", Age = 19 }
};// 篩選出年齡大于20歲的學生
var filtered = students.Where(s => s.Age > 20);// 輸出:Bob(Age=22)
- 進階用法
Where
可以結合索引或復雜條件:
// 篩選偶數位置的元素(索引從0開始)
var evenIndices = numbers.Where((n, index) => index % 2 == 0);// 多條件組合(年齡在20到25歲之間)
var filtered = students.Where(s => s.Age >= 20 && s.Age <= 25);
- 補充說明
Where
是 LINQ 中最基礎且常用的篩選方法,通常與其他方法(如Select
,OrderBy
,Take
等)組合使用,構建復雜的查詢邏輯。例如:
var query = students.Where(s => s.Age > 20) // 篩選條件.OrderBy(s => s.Name) // 排序.Select(s => s.Name) // 投影.Take(2); // 取前2個結果
4. Take
從集合的開頭取指定數量的元素。
IEnumerable<TSource> Take<TSource>(this IEnumerable<TSource> source,int count
);
- 案例
var numbers = new List<int> { 1, 2, 3, 4, 5 };// 取前3個元素
var firstThree = numbers.Take(3);// 輸出:1, 2, 3
5. TakeWhile
從集合的開頭開始,取元素直到條件不滿足為止。
IEnumerable<TSource> TakeWhile<TSource>(this IEnumerable<TSource> source,Func<TSource, bool> predicate
);
- 案例
var numbers = new List<int> { 1, 3, 5, 4, 2 };// 取元素直到遇到第一個小于當前元素的數
var taken = numbers.TakeWhile((n, index) => n > numbers[index - 1]);// 輸出:1, 3, 5(因為 4 < 5 時停止)
6. SkipWhile
跳過滿足條件的元素,直到條件不滿足為止,之后返回剩余元素。
IEnumerable<TSource> SkipWhile<TSource>(this IEnumerable<TSource> source,Func<TSource, bool> predicate
);
- 案例
var numbers = new List<int> { 1, 3, 5, 4, 2 };// 跳過元素直到遇到第一個小于當前元素的數
var skipped = numbers.SkipWhile((n, index) => n > numbers[index - 1]);// 輸出:4, 2(從索引3開始)
7. Join
將兩個集合通過關聯鍵連接(類似SQL的INNER JOIN)。
IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer,IEnumerable<TInner> inner,Func<TOuter, TKey> outerKeySelector,Func<TInner, TKey> innerKeySelector,Func<TOuter, TInner, TResult> resultSelector
);
- 案例
var students = new List<Student>
{new Student { Id = 1, Name = "Alice" },new Student { Id = 2, Name = "Bob" }
};var enrollments = new List<Enrollment>
{new Enrollment { StudentId = 1, Course = "Math" },new Enrollment { StudentId = 2, Course = "Physics" }
};var joined = students.Join(enrollments,s => s.Id,e => e.StudentId,(s, e) => new { s.Name, e.Course }
);// 輸出:
// { Name = "Alice", Course = "Math" }
// { Name = "Bob", Course = "Physics" }
8. GroupJoin
將兩個集合通過關聯鍵連接,并返回分組后的結果(類似SQL的LEFT JOIN)。
IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer,IEnumerable<TInner> inner,Func<TOuter, TKey> outerKeySelector,Func<TInner, TKey> innerKeySelector,Func<TOuter, IEnumerable<TInner>, TResult> resultSelector
);
- 案例
var students = new List<Student>
{new Student { Id = 1, Name = "Alice" },new Student { Id = 2, Name = "Bob" }
};var enrollments = new List<Enrollment>
{new Enrollment { StudentId = 1, Course = "Math" },new Enrollment { StudentId = 1, Course = "Physics" },new Enrollment { StudentId = 2, Course = "Chemistry" }
};var grouped = students.GroupJoin(enrollments,s => s.Id,e => e.StudentId,(s, es) => new { s.Name, Courses = es.Select(e => e.Course) }
);// 輸出:
// { Name = "Alice", Courses = ["Math", "Physics"] }
// { Name = "Bob", Courses = ["Chemistry"] }
9. OrderBy
按升序對集合排序。
IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source,Func<TSource, TKey> keySelector
);
- 案例
var students = new List<Student>
{new Student { Id = 3, Name = "Charlie" },new Student { Id = 1, Name = "Alice" }
};var sorted = students.OrderBy(s => s.Id);// 輸出:按Id升序排列的列表
10. OrderByDescending
按降序對集合排序。
IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source,Func<TSource, TKey> keySelector
);
- 案例
var students = new List<Student>
{new Student { Id = 3, Name = "Charlie" },new Student { Id = 1, Name = "Alice" }
};var sorted = students.OrderByDescending(s => s.Id);// 輸出:按Id降序排列的列表
11. ThenBy
在已有排序的基礎上進行二次排序。
IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source,Func<TSource, TKey> keySelector
);
- 案例
var students = new List<Student>
{new Student { Id = 1, Name = "Alice", Age = 20 },new Student { Id = 2, Name = "Bob", Age = 20 }
};var sorted = students.OrderBy(s => s.Age).ThenBy(s => s.Name);// 先按年齡排序,再按姓名排序
12. Concat
將兩個集合連接成一個集合。
IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second
);
- 案例
var list1 = new List<int> { 1, 2 };
var list2 = new List<int> { 3, 4 };var concatenated = list1.Concat(list2);// 輸出:1, 2, 3, 4
13. Zip
將兩個集合按元素順序配對,直到較短的集合結束。
IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first,IEnumerable<TSecond> second,Func<TFirst, TSecond, TResult> resultSelector
);
- 案例
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<string> { "a", "b" };var zipped = list1.Zip(list2, (n, s) => $"{n}-{s}");// 輸出:["1-a", "2-b"](較短的集合決定長度)
14. Distinct
返回集合中唯一(不重復)的元素。
IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source
);
- 案例
var numbers = new List<int> { 1, 2, 2, 3 };var distinct = numbers.Distinct();// 輸出:1, 2, 3
15. Except
返回第一個集合中存在但不在第二個集合中的元素。
IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second
);
- 案例
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 2, 3, 4 };var except = list1.Except(list2);// 輸出:1(list1中有但不在list2中的元素)
以下是關于 Union
, Intersect
和 Concat
的詳細說明,補充到之前的 LINQ 方法列表中:
16. Union
返回兩個集合的并集(去重后的所有元素)。
IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second
);
first
: 第一個集合。second
: 第二個集合。- 案例
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 3, 4, 5 };var union = list1.Union(list2);// 輸出:1, 2, 3, 4, 5(去重后的并集)
- 進階用法
可自定義比較器:
var unionWithComparer = list1.Union(list2, StringComparer.OrdinalIgnoreCase);
17. Intersect
返回兩個集合的交集(同時存在于兩個集合的元素)。
IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second
);
- 案例
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 3, 4, 5 };var intersect = list1.Intersect(list2);// 輸出:3(唯一共同元素)
- 進階用法
自定義比較器:
var intersectWithComparer = list1.Intersect(list2, StringComparer.OrdinalIgnoreCase);
18. Concat
將兩個集合連接成一個集合(保留重復元素,順序為 first
后接 second
)。
IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second
);
- 案例
var list1 = new List<int> { 1, 2 };
var list2 = new List<int> { 2, 3 };var concatenated = list1.Concat(list2);// 輸出:1, 2, 2, 3(保留重復元素)
- 對比總結
方法 | 功能 | 是否去重 | 示例 |
---|---|---|---|
Union | 并集(去重) | 是 | {1,2} ∪ {2,3} → {1,2,3} |
Intersect | 交集(共同元素) | 是 | {1,2} ∩ {2,3} → {2} |
Concat | 連接(保留重復,順序拼接) | 否 | {1,2} + {2,3} → {1,2,2,3} |
19. Reverse
反轉集合的順序。
IEnumerable<TSource> Reverse<TSource>(this IEnumerable<TSource> source
);
- 案例
var numbers = new List<int> { 1, 2, 3 };var reversed = numbers.Reverse();// 輸出:3, 2, 1
20. SequenceEqual
比較兩個集合的元素是否完全相同(順序和內容)。
bool SequenceEqual<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second
);
- 案例
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 1, 2, 3 };var equal = list1.SequenceEqual(list2); // truevar list3 = new List<int> { 1, 2 };
var notEqual = list1.SequenceEqual(list3); // false
21. ToLookup
將集合轉換為 ILookup<TKey, TElement>
,按鍵分組。
ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(this IEnumerable<TSource> source,Func<TSource, TKey> keySelector,Func<TSource, TElement> elementSelector
);
- 案例
var students = new List<Student>
{new Student { Id = 1, Name = "Alice", Age = 20 },new Student { Id = 2, Name = "Bob", Age 20 }
};var lookup = students.ToLookup(s => s.Age, s => s.Name);// 查詢年齡為20的姓名列表:
var names = lookup[20]; // ["Alice", "Bob"]
22. OfType
過濾集合中符合指定類型的元素。
IEnumerable<TResult> OfType<TResult>(this IEnumerable source
);
- 案例
var mixedList = new object[] { 1, "text", 3.14 };var numbers = mixedList.OfType<int>();// 輸出:1(只保留int類型)
23. Cast
強制轉換集合中所有元素為指定類型。
IEnumerable<TResult> Cast<TResult>(this IEnumerable source
);
- 案例
var mixedList = new object[] { 1, "text", 3.14 };var strings = mixedList.Cast<string>(); // 拋出異常,因為包含非字符串類型
24. Range
生成一個指定范圍的整數序列。
IEnumerable<int> Range(int start,int count
);
- 案例
var numbers = Enumerable.Range(1, 5); // 生成1到5的整數// 輸出:1, 2, 3, 4, 5
22. Repeat
生成指定次數的重復元素序列。
IEnumerable<TSource> Repeat<TSource>(TSource element,int count
);
- 案例
var repeated = Enumerable.Repeat("Hello", 3);// 輸出:["Hello", "Hello", "Hello"]
25. Prepend
在集合的開頭添加一個元素。
IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> source,TSource element
);
- 案例
var numbers = new List<int> { 2, 3 };
var prepended = numbers.Prepend(1);// 輸出:1, 2, 3
總結
- Projection(投影):
Select
,SelectMany
- Filtering(過濾):
Take
,TakeWhile
,SkipWhile
,Where
- Joins(連接):
Join
,GroupJoin
- Sorting(排序):
OrderBy
,OrderByDescending
,ThenBy
- Combining(結合):
Concat
,Zip
- Set Operations(集合操作):
Distinct
,Except
,Union?
,Intersect?
,Concat?
去重、并集、交集、差集和連接? - Transformation(轉換):
Reverse
,ToLookup
,OfType
,Cast
,Range
,Repeat
,Prepend
注意:
?性能問題?:
不當使用LINQ可能會導致性能下降,尤其是在處理大數據集時。建議盡早使用Where來過濾數據,減少后續操作的數據量?
?過早枚舉?:
當使用foreach循環遍歷LINQ查詢結果時,如果查詢結果是一個延遲執行的序列(如IEnumerable),那么查詢會在第一次遍歷時被執行?