C# 关于LINQ语法和类型的使用

发布于:2025-06-18 ⋅ 阅读:(21) ⋅ 点赞:(0)

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, IntersectConcat 的详细说明,补充到之前的 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, ExceptUnion‌Intersect‌Concat‌ 去重、并集、交集、差集和连接‌
  • Transformation(转换): Reverse, ToLookup, OfType, Cast, Range, Repeat, Prepend

注意:
‌性能问题‌:不当使用LINQ可能会导致性能下降,尤其是在处理大数据集时。建议尽早使用Where来过滤数据,减少后续操作的数据量‌
‌过早枚举‌:当使用foreach循环遍历LINQ查询结果时,如果查询结果是一个延迟执行的序列(如IEnumerable),那么查询会在第一次遍历时被执行‌


网站公告

今日签到

点亮在社区的每一天
去签到