LINQ 中常用的方法逐一进行举例说明

下面将对 LINQ 中常用的方法逐一进行举例说明,涵盖其基本用法和核心功能:

1. Where(筛选元素)

根据条件筛选序列中的元素,保留满足条件的项。
var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
// 筛选偶数
var evenNumbers = numbers.Where(n => n % 2 == 0); 
// 结果:2, 4, 6

 

2. OfType(筛选指定类型元素)

从非泛型集合中筛选出指定类型的元素(自动过滤不匹配类型)。 
var mixed = new ArrayList { 1, "two", 3, "four", 5 };
// 筛选int类型元素
var ints = mixed.OfType<int>(); 
// 结果:1, 3, 5

  

3. Skip(跳过前 N 个元素)

跳过序列中前n个元素,返回剩余元素。
var numbers = new List<int> { 1, 2, 3, 4, 5 };
// 跳过前2个元素
var result = numbers.Skip(2); 
// 结果:3, 4, 5

 

 4. Take(获取前 N 个元素)
获取序列中前n个元素。
var numbers = new List<int> { 1, 2, 3, 4, 5 };
// 获取前3个元素
var result = numbers.Take(3); 
// 结果:1, 2, 3

 

5. SkipLast & TakeLast(跳过 / 获取最后 N 个元素)

  • SkipLast(n):跳过序列最后n个元素
  • TakeLast(n):获取序列最后n个元素
    (.NET Core 3.0+ 支持)
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var skipLast2 = numbers.SkipLast(2); // 结果:1, 2, 3
var takeLast2 = numbers.TakeLast(2); // 结果:4, 5

 

6. SkipWhile & TakeWhile(条件跳过 / 获取)

  • SkipWhile:跳过满足条件的连续元素,直到遇到不满足条件的元素
  • TakeWhile:获取满足条件的连续元素,直到遇到不满足条件的元素
var numbers = new List<int> { 1, 2, 3, 4, 3, 2, 1 };
// 跳过小于3的元素,直到第一个≥3的元素(3)
var skipResult = numbers.SkipWhile(n => n < 3); // 3, 4, 3, 2, 1

// 获取小于3的元素,直到第一个≥3的元素(3)
var takeResult = numbers.TakeWhile(n => n < 3); // 1, 2

 

7. Select(投影转换)

将序列中的每个元素转换为新形式(提取属性或转换类型)。
var people = new List<Person> { 
    new Person { Name = "Alice", Age = 25 },
    new Person { Name = "Bob", Age = 30 }
};
// 提取姓名
var names = people.Select(p => p.Name); 
// 结果:"Alice", "Bob"

 

8. Select with index(带索引的投影)

转换元素时同时使用元素的索引(从 0 开始)。
var fruits = new List<string> { "苹果", "香蕉", "橙子" };
// 结合索引生成新字符串
var indexedFruits = fruits.Select((fruit, index) => $"{index + 1}. {fruit}");
// 结果:"1. 苹果", "2. 香蕉", "3. 橙子"

 

9. SelectMany(展平集合)

将 "集合的集合" 展平为单个序列(如每个元素是列表,合并为一个列表)。
var students = new List<Student> {
    new Student { Name = "Alice", Courses = new List<string> { "Math", "English" } },
    new Student { Name = "Bob", Courses = new List<string> { "Physics", "History" } }
};
// 展平所有课程
var allCourses = students.SelectMany(s => s.Courses); 
// 结果:"Math", "English", "Physics", "History"

 

 10. SelectMany with index(带索引的展平)
展平集合时同时使用元素的索引。
var groups = new List<List<int>> { new() { 1, 2 }, new() { 3, 4 } };
// 展平并标记原组索引
var result = groups.SelectMany((group, groupIndex) => 
    group.Select(num => $"(组{groupIndex}): {num}")
);
// 结果:"(组0): 1", "(组0): 2", "(组1): 3", "(组1): 4"

 

11. Cast(强制类型转换)

将序列元素强制转换为指定类型(不匹配类型会抛异常,与OfType的区别:OfType过滤不匹配类型,Cast强制转换)。
var mixed = new ArrayList { 1, 2, 3 };
// 强制转换为int(若有非int元素会抛InvalidCastException)
var ints = mixed.Cast<int>(); 
// 结果:1, 2, 3

 

12. Chunk(拆分序列为块)

将序列拆分为指定大小的子序列(.NET 6+ 支持)。
var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7 };
// 按大小为2拆分
var chunks = numbers.Chunk(2); 
// 结果:[1,2], [3,4], [5,6], [7]

 

13. Deferred Execution vs Immediate Execution(延迟执行 vs 立即执行)

  • 延迟执行:LINQ 方法(如WhereSelect)不会立即执行,直到枚举结果(如foreachToList)时才执行(节省内存)。
  • 立即执行:触发枚举的方法(如ToListCount)会立即执行并生成结果。
var numbers = new List<int> { 1, 2, 3 };
// 延迟执行:此时未计算
var query = numbers.Where(n => n > 1); 

numbers.Add(4); // 修改源集合
var result = query.ToList(); // 立即执行:此时才计算,包含新增的4
// 结果:2, 3, 4

 

14. Any(存在满足条件的元素)

检查序列中是否存在至少一个满足条件的元素(无参数时检查是否非空)。
var numbers = new List<int> { 1, 2, 3 };
bool hasEven = numbers.Any(n => n % 2 == 0); // true(存在偶数2)
bool isEmpty = numbers.Any(); // false(序列非空)

 

15. All(所有元素满足条件)

检查序列中所有元素是否都满足条件。
var numbers = new List<int> { 2, 4, 6 };
bool allEven = numbers.All(n => n % 2 == 0); // true(全是偶数)

 

16. Contains(包含指定元素)

检查序列是否包含指定元素(默认使用EqualityComparer比较)。
var fruits = new List<string> { "苹果", "香蕉" };
bool hasBanana = fruits.Contains("香蕉"); // true

 

17. Append & Prepend(添加元素到末尾 / 开头)

  • Append:在序列末尾添加一个元素
  • Prepend:在序列开头添加一个元素
var numbers = new List<int> { 2, 3 };
var withOne = numbers.Prepend(1); // 1, 2, 3
var withFour = numbers.Append(4); // 2, 3, 4

 

18. Count(元素数量)

  • 无参数:返回序列元素总数
  • 带条件:返回满足条件的元素数量
var numbers = new List<int> { 1, 2, 3, 4, 5 };
int total = numbers.Count(); // 5
int evenCount = numbers.Count(n => n % 2 == 0); // 2(偶数有2、4)

 

19. TryGetNonEnumeratedCount(非枚举获取计数)

尝试在不枚举序列的情况下获取元素数量(提高性能,适用于已实现ICollection的集合)。
var list = new List<int> { 1, 2, 3 };
if (list.TryGetNonEnumeratedCount(out int count))
{
    Console.WriteLine(count); // 3(无需枚举)
}

 

20. Max(最大值)

获取序列中的最大值。
var numbers = new List<int> { 3, 1, 4, 2 };
int max = numbers.Max(); // 4

 

21. MaxBy(按键取最大值元素)

根据指定键选择器,获取键值最大的元素。
var people = new List<Person> { 
    new Person { Name = "Alice", Age = 25 },
    new Person { Name = "Bob", Age = 30 }
};
// 取年龄最大的人
Person oldest = people.MaxBy(p => p.Age); // Bob(30岁)

 

22. Min & MinBy(最小值 / 按键取最小值元素)

  • Min:获取序列中的最小值
  • MinBy:根据键获取键值最小的元素
var numbers = new List<int> { 3, 1, 4, 2 };
int min = numbers.Min(); // 1

var people = new List<Person> { /* 同上 */ };
Person youngest = people.MinBy(p => p.Age); // Alice(25岁)

 

23. Sum(总和)

计算序列中元素的总和。
var numbers = new List<int> { 1, 2, 3 };
int sum = numbers.Sum(); // 6

 

24. Average(平均值)

计算序列中元素的平均值(返回double)。
var numbers = new List<int> { 1, 2, 3, 4 };
double avg = numbers.Average(); // 2.5

 

25. LongCount(长整数计数)

返回long类型的元素数量(适用于元素超过int.MaxValue的大集合)。
var largeList = Enumerable.Range(1, 1_000_000_000);
long count = largeList.LongCount(); // 1000000000(超过int.MaxValue时使用)

 

26. Aggregate(聚合操作)

对序列执行累积操作(自定义聚合逻辑),有 3 个重载:
  • 重载 1:使用初始值和累加器
var numbers = new List<int> { 1, 2, 3, 4 };
// 计算乘积(初始值1,累加器:acc * current)
int product = numbers.Aggregate(1, (acc, current) => acc * current); // 24
  • 重载 2:累加后再转换结果
var words = new List<string> { "Hello", "World" };
// 拼接字符串后转为大写
string result = words.Aggregate("", (acc, word) => acc + " " + word, final => final.Trim().ToUpper());
// 结果:"HELLO WORLD"
  • 重载 3:无初始值(使用第一个元素作为初始值)
var numbers = new List<int> { 1, 2, 3 };
// 累加(初始值为1,然后1+2=3,3+3=6)
int sum = numbers.Aggregate((acc, current) => acc + current); // 6

 

27. First & FirstOrDefault(第一个元素)

  • First:返回序列中第一个元素(序列为空或无匹配项时抛异常)
  • FirstOrDefault:返回第一个元素,无匹配项时返回默认值(如null0
var numbers = new List<int> { 2, 4, 6 };
int firstEven = numbers.First(n => n % 2 == 0); // 2
int firstOdd = numbers.FirstOrDefault(n => n % 2 != 0); // 0(无奇数,返回默认值)

 

28. Single & SingleOrDefault(唯一元素)

  • Single:返回序列中唯一满足条件的元素(多个匹配项或无匹配项时抛异常)
  • SingleOrDefault:返回唯一元素,无匹配项时返回默认值,多个匹配项时抛异常
var numbers = new List<int> { 1, 2, 3 };
int singleEven = numbers.Single(n => n == 2); // 2(唯一匹配)
int singleOdd = numbers.SingleOrDefault(n => n == 4); // 0(无匹配)

 

29. Last & LastOrDefault(最后一个元素)

  • Last:返回序列中最后一个元素(序列为空时抛异常)
  • LastOrDefault:返回最后一个元素,无匹配项时返回默认值
var numbers = new List<int> { 1, 2, 3 };
int last = numbers.Last(); // 3
int lastEven = numbers.LastOrDefault(n => n % 2 == 0); // 2

 

30. ElementAt & ElementAtOrDefault(按索引取元素)

  • ElementAt:返回指定索引处的元素(索引越界时抛异常)
  • ElementAtOrDefault:返回指定索引处的元素,索引越界时返回默认值
var numbers = new List<int> { 1, 2, 3 };
int second = numbers.ElementAt(1); // 2(索引从0开始)
int fifth = numbers.ElementAtOrDefault(4); // 0(索引越界)

 

31. DefaultIfEmpty(空序列时返回默认值)

如果序列为空,返回包含默认值的序列;否则返回原序列。
var emptyList = new List<int>();
var result = emptyList.DefaultIfEmpty(0); // 结果:0(原序列为空,返回默认值0)

 

32. ToArray(转换为数组)

将序列转换为T[]数组。
var numbers = new List<int> { 1, 2, 3 };
int[] array = numbers.ToArray(); // 类型:int[],值:[1,2,3]

 

33. ToList(转换为列表)

将序列转换为List<T>
var numbers = new int[] { 1, 2, 3 };
List<int> list = numbers.ToList(); // 类型:List<int>,值:{1,2,3}

 

34. ToDictionary(转换为字典)

将序列转换为Dictionary<TKey, TValue>(需指定键选择器,确保键唯一)。
var people = new List<Person> { 
    new Person { Id = 1, Name = "Alice" },
    new Person { Id = 2, Name = "Bob" }
};
// 以Id为键,Name为值
var dict = people.ToDictionary(p => p.Id, p => p.Name); 
// 结果:{1: "Alice", 2: "Bob"}

 

35. ToHashSet(转换为哈希集)

将序列转换为HashSet<T>(自动去重)。
var numbers = new List<int> { 1, 2, 2, 3 };
HashSet<int> set = numbers.ToHashSet(); // 结果:{1, 2, 3}(去重)

 

36. ToLookup(创建 Lookup 集合)

类似字典,但键可以映射到多个值(无需确保键唯一)。
var people = new List<Person> { 
    new Person { Name = "Alice", Age = 25 },
    new Person { Name = "Bob", Age = 25 },
    new Person { Name = "Charlie", Age = 30 }
};
// 按年龄分组(键:年龄,值:该年龄的人)
ILookup<int, Person> lookup = people.ToLookup(p => p.Age);
// 访问25岁的人:lookup[25] → Alice, Bob

 

37. ToEnumerable & ToQueryable(转换为 IEnumerable/Queryable)

  • ToEnumerable:将IQueryable转换为IEnumerable(客户端执行)
  • ToQueryable:将IEnumerable转换为IQueryable(适用于 LINQ to SQL 等)

38. Enumerable.Range(生成整数范围)

生成指定起始值和数量的整数序列。
// 从1开始,生成5个整数
var range = Enumerable.Range(1, 5); // 结果:1, 2, 3, 4, 5

 

39. Enumerable.Repeat(生成重复元素)

生成包含指定元素重复n次的序列。
// 重复"Hi" 3次
var repeated = Enumerable.Repeat("Hi", 3); // 结果:"Hi", "Hi", "Hi"

 

40. Enumerable.Empty(空序列)

返回指定类型的空序列(比new List<T>()更高效)。
IEnumerable<int> empty = Enumerable.Empty<int>(); // 空序列

 

41. Distinct(去重)

去除序列中的重复元素(默认使用EqualityComparer)。
var numbers = new List<int> { 1, 2, 2, 3, 3, 3 };
var unique = numbers.Distinct(); // 结果:1, 2, 3

 

42. DistinctBy(按键去重)

根据指定键选择器去除重复元素(保留第一个出现的元素)。
var people = new List<Person> { 
    new Person { Name = "Alice", Age = 25 },
    new Person { Name = "Bob", Age = 25 }, // 与Alice年龄相同
    new Person { Name = "Charlie", Age = 30 }
};
// 按年龄去重(保留第一个25岁的Alice)
var uniqueAges = people.DistinctBy(p => p.Age); 
// 结果:Alice(25)、Charlie(30)

 

43. 集合操作理论(Union/Intersect/Except)

  • Union:并集(合并两个序列,去重)
  • Intersect:交集(两个序列都包含的元素)
  • Except:差集(第一个序列有、第二个序列没有的元素)

44. Union(并集)

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(去重)

 

45. Intersect(交集)

var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 3, 4, 5 };
var intersect = list1.Intersect(list2); // 结果:3(两序列共有的元素)

 

46. Except(差集)

var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 3, 4, 5 };
var except = list1.Except(list2); // 结果:1, 2(list1有、list2没有的元素)

 

47. UnionBy & IntersectBy & ExceptBy(按键的集合操作)

与上述集合操作类似,但根据指定键进行比较。
var people1 = new List<Person> { new() { Id = 1 }, new() { Id = 2 } };
var people2 = new List<Person> { new() { Id = 2 }, new() { Id = 3 } };

// 按Id取并集
var unionBy = people1.UnionBy(people2, p => p.Id); // Id=1, 2, 3

 

48. SequenceEqual(序列是否相等)

检查两个序列的元素是否数量相同且顺序、值均一致。
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 1, 2, 3 };
var list3 = new List<int> { 1, 3, 2 };
bool equal1 = list1.SequenceEqual(list2); // true
bool equal2 = list1.SequenceEqual(list3); // false(顺序不同)

 

49. Zip(合并两个序列)

将两个序列按位置合并为元组序列(长度取较短序列)。
var numbers = new List<int> { 1, 2, 3 };
var words = new List<string> { "One", "Two", "Three" };
var zipped = numbers.Zip(words, (n, w) => $"{n}: {w}");
// 结果:"1: One", "2: Two", "3: Three"

 

50. Join(连接两个序列)

类似数据库内连接,根据键匹配两个序列的元素。
var students = new List<Student> { new() { Id = 1, Name = "Alice" } };
var scores = new List<Score> { new() { StudentId = 1, Value = 90 } };

// 按StudentId连接学生和分数
var joined = students.Join(
    scores,
    s => s.Id,          // 学生的键
    sc => sc.StudentId, // 分数的键
    (s, sc) => new { s.Name, sc.Value } // 结果投影
);
// 结果:{ Name = "Alice", Value = 90 }

 

51. GroupJoin(分组连接)

类似左外连接,将第二个序列按键分组后与第一个序列连接。
var courses = new List<Course> { new() { Id = 1, Name = "Math" } };
var students = new List<Student> { 
    new() { Id = 1, Name = "Alice", CourseId = 1 },
    new() { Id = 2, Name = "Bob", CourseId = 1 }
};

// 按CourseId分组连接课程和学生
var groupJoined = courses.GroupJoin(
    students,
    c => c.Id,          // 课程的键
    s => s.CourseId,    // 学生的键
    (c, studentsInCourse) => new { 
        CourseName = c.Name,
        Students = studentsInCourse.Select(s => s.Name)
    }
);
// 结果:{ CourseName = "Math", Students = ["Alice", "Bob"] }

 

52. Concat(连接序列)

将两个序列首尾连接(与Union的区别:Concat不去重)。
var list1 = new List<int> { 1, 2 };
var list2 = new List<int> { 2, 3 };
var concat = list1.Concat(list2); // 结果:1, 2, 2, 3(保留重复)

 

53. GroupBy(分组)

根据键选择器将序列分组,返回IGrouping<TKey, TElement>集合。
var people = new List<Person> { 
    new() { Name = "Alice", Age = 25 },
    new() { Name = "Bob", Age = 25 },
    new() { Name = "Charlie", Age = 30 }
};
// 按年龄分组
var groups = people.GroupBy(p => p.Age);
// 结果:
// 键25:Alice, Bob
// 键30:Charlie

 

54. OrderBy(升序排序)

按指定键对序列进行升序排序。
var people = new List<Person> { 
    new() { Name = "Bob", Age = 30 },
    new() { Name = "Alice", Age = 25 }
};
// 按年龄升序
var ordered = people.OrderBy(p => p.Age); 
// 结果:Alice(25)、Bob(30)

 

55. OrderByDescending(降序排序)

按指定键对序列进行降序排序。
// 按年龄降序
var orderedDesc = people.OrderByDescending(p => p.Age); 
// 结果:Bob(30)、Alice(25)

 

56. ThenBy & ThenByDescending(二次排序)

OrderBy/OrderByDescending之后进行二次排序(按第二个键)。
var people = new List<Person> { 
    new() { Name = "Bob", Age = 25 },
    new() { Name = "Alice", Age = 25 }, // 与Bob年龄相同
    new() { Name = "Charlie", Age = 30 }
};
// 先按年龄升序,再按姓名升序
var ordered = people.OrderBy(p => p.Age).ThenBy(p => p.Name);
// 结果:Alice(25)、Bob(25)、Charlie(30)

 

57. Reverse(反转序列)

反转序列中元素的顺序。
var numbers = new List<int> { 1, 2, 3 };
var reversed = numbers.Reverse(); // 结果:3, 2, 1

 

58. PLINQ(并行 LINQ)

通过AsParallel()启用并行查询,利用多线程加速处理(适用于大数据量)。
var numbers = Enumerable.Range(1, 1_000_000);
// 并行计算偶数的平方和(自动利用多线程)
var sum = numbers.AsParallel()
                .Where(n => n % 2 == 0)
                .Select(n => n * n)
                .Sum();

以上涵盖了 LINQ 中最常用的方法,每个方法都有其特定场景,实际使用中常结合链式操作(如Where+Select+OrderBy)处理复杂需求。

posted @ 2025-07-15 23:41  奇微  阅读(69)  评论(0)    收藏  举报