常用语法,具体问题具体分析
-
-
- 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); // true
var 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),那么查询会在第一次遍历时被执行