LINQ 中被低估的十大方法
LINQ(Language Integrated Query)作为 .NET 框架中的一个强大特性,允许开发者以一种简洁且易读的方式查询集合。尽管像 Where
, Select
, OrderBy
, 和 GroupBy
这样的方法被广泛使用和赞赏,但仍有许多其他 LINQ 方法虽然经常被忽视,但却极其有用。在本文中,我们将探讨十个被低估的 LINQ 方法,并通过示例来帮助你充分利用它们的强大功能。
一、Aggregate
Aggregate
方法将一个累积函数应用于序列,这对于执行复杂的计算或聚合非常有用。
// 使用 System 和 System.Linq 命名空间
using System;
using System.Linq;
class Program
{
static void Main()
{
// 定义一个整数数组
var numbers = new[] { 1, 2, 3, 4, 5 };
// 计算所有数字的总和
var sum = numbers.Aggregate((acc, x) => acc + x); // acc 是累积器,x 是当前元素
// 输出总和
Console.WriteLine($"Sum: {sum}");
// 计算所有数字的乘积
var product = numbers.Aggregate((acc, x) => acc * x); // 使用相同的累积器模式
// 输出乘积
Console.WriteLine($"Product: {product}");
}
}
二、Zip
Zip
方法通过指定的函数将两个序列中的元素成对组合起来。
// 引入必要的命名空间
using System;
using System.Linq;
class Program
{
static void Main()
{
// 创建两个数组
var numbers = new[] { 1, 2, 3 };
var words = new[] { "one", "two", "three" };
// 将两个数组中的元素成对组合
var zipped = numbers.Zip(words, (n, w) => $"{n} is {w}"); // n 是 numbers 数组中的元素,w 是 words 数组中的元素
// 遍历组合后的序列并打印
foreach (var item in zipped)
{
Console.WriteLine(item);
}
}
}
三、Chunk
Chunk
方法将序列分割成指定大小的块。
using System;
using System.Linq;
class Program
{
static void Main()
{
// 创建一个从 1 到 10 的整数序列
var numbers = Enumerable.Range(1, 10);
// 将序列分割成每三个元素一组
var chunks = numbers.Chunk(3);
// 遍历每个块并打印
foreach (var chunk in chunks)
{
Console.WriteLine(string.Join(", ", chunk)); // 将每个块内的元素以逗号分隔的形式打印出来
}
}
}
四、TakeWhile 和 SkipWhile
TakeWhile
方法返回序列中的元素直到指定条件不再成立;而 SkipWhile
方法则跳过满足条件的元素,然后返回剩余的元素。
using System;
using System.Linq;
class Program
{
static void Main()
{
// 创建一个整数数组
var numbers = new[] { 1, 2, 3, 4, 5, 6 };
// 取出小于 4 的所有元素
var takeWhileLessThanFour = numbers.TakeWhile(n => n < 4);
Console.WriteLine("TakeWhile < 4: " + string.Join(", ", takeWhileLessThanFour));
// 跳过小于 4 的所有元素
var skipWhileLessThanFour = numbers.SkipWhile(n => n < 4);
Console.WriteLine("SkipWhile < 4: " + string.Join(", ", skipWhileLessThanFour));
}
}
五、DistinctBy
DistinctBy
方法基于指定的键选择器返回序列中的唯一元素。此方法不是标准 LINQ 方法的一部分,通常需要使用扩展方法或第三方库如 MoreLINQ。
using System;
using System.Collections.Generic;
using System.Linq;
using MoreLinq; // 引入 MoreLINQ 库以使用 DistinctBy 方法
class Program
{
static void Main()
{
// 创建一个包含重复名字的人列表
var people = new List<Person>
{
new Person { Name = "Alice", Age = 30 },
new Person { Name = "Bob", Age = 40 },
new Person { Name = "Alice", Age = 35 },
};
// 根据名字筛选出唯一的元素
var distinctNames = people.DistinctBy(p => p.Name);
// 打印每个唯一的名字
foreach (var person in distinctNames)
{
Console.WriteLine(person.Name);
}
}
// 定义 Person 类
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
}
六、GroupBy
GroupBy
方法根据指定的键选择器函数将序列中的元素分组。
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
// 创建一个人的列表
var people = new List<Person>
{
new Person { Name = "Alice", Age = 30 },
new Person { Name = "Bob", Age = 40 },
new Person { Name = "Charlie", Age = 30 },
};
// 根据年龄分组
var groupedByAge = people.GroupBy(p => p.Age);
// 打印每个年龄组的信息
foreach (var group in groupedByAge)
{
Console.WriteLine($"Age: {group.Key}");
foreach (var person in group)
{
Console.WriteLine($" - {person.Name}");
}
}
}
// 定义 Person 类
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
}
七、ToDictionary
ToDictionary
方法根据指定的键选择器和元素选择器函数从序列创建字典。
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
// 创建一个人的列表
var people = new List<Person>
{
new Person { Name = "Alice", Age = 30 },
new Person { Name = "Bob", Age = 40 },
new Person { Name = "Charlie", Age = 35 },
};
// 将人列表转换为字典,键为人名,值为年龄
var dictionary = people.ToDictionary(p => p.Name, p => p.Age);
// 遍历字典并打印
foreach (var kvp in dictionary)
{
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}
}
// 定义 Person 类
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
}
八、SelectMany
SelectMany
方法将序列中的每个元素映射到一个 IEnumerable<T>
并将结果序列扁平化为单一序列。
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
// 创建一个人的列表,每个人都有宠物列表
var people = new List<Person>
{
new Person { Name = "Alice", Pets = new List<string> { "Cat", "Dog" } },
new Person { Name = "Bob", Pets = new List<string> { "Fish" } },
};
// 将每个人的宠物列表扁平化为一个单一的宠物列表
var allPets = people.SelectMany(p => p.Pets);
// 打印所有宠物
foreach (var pet in allPets)
{
Console.WriteLine(pet);
}
}
// 定义 Person 类
class Person
{
public string Name { get; set; }
public List<string> Pets { get; set; }
}
}
九、Except
Except
方法产生两个序列之间的差集,即第一个序列中有但在第二个序列中没有的元素。
using System;
using System.Linq;
class Program
{
static void Main()
{
// 创建两个整数数组
var numbers1 = new[] { 1, 2, 3, 4, 5 };
var numbers2 = new[] { 3, 4, 5, 6, 7 };
// 获取第一个数组中不在第二个数组中的元素
var difference = numbers1.Except(numbers2);
// 打印差集
Console.WriteLine("Difference: " + string.Join(", ", difference));
}
}
十、Partition
Partition
方法(自 .NET 6 起可用)返回两个序列:一个包含满足指定条件的元素,另一个包含不满足条件的元素。
using System;
using System.Linq;
class Program
{
static void Main()
{
// 创建一个整数数组
var numbers = new[] { 1, 2, 3, 4, 5, 6 };
// 根据是否为偶数将数组分成两部分
var (evens, odds) = numbers.Partition(n => n % 2 == 0);
// 打印偶数
Console.WriteLine("Evens: " + string.Join(", ", evens));
// 打印奇数
Console.WriteLine("Odds: " + string.Join(", ", odds));
}
}
结论
LINQ 是 .NET 生态系统中的一个强大工具,提供了大量用于查询和操作集合的方法。虽然有些方法被广泛知晓和使用,但其他方法如 Aggregate
, Zip
, Chunk
, DistinctBy
, 和 Partition
可以为各种编程场景提供独特而高效的解决方案。通过理解和利用这些被低估的 LINQ 方法,你可以写出更加简洁、可读性强且高效的代码。