LINQ 中被低估的十大方法

发布:2024-09-06 22:56 阅读:23 点赞:0

LINQ(Language Integrated Query)作为 .NET 框架中的一个强大特性,允许开发者以一种简洁且易读的方式查询集合。尽管像 WhereSelectOrderBy, 和 GroupBy 这样的方法被广泛使用和赞赏,但仍有许多其他 LINQ 方法虽然经常被忽视,但却极其有用。在本文中,我们将探讨十个被低估的 LINQ 方法,并通过示例来帮助你充分利用它们的强大功能。

一、Aggregate

Aggregate 方法将一个累积函数应用于序列,这对于执行复杂的计算或聚合非常有用。

// 使用 System 和 System.Linq 命名空间
using System;
using System.Linq;

class Program
{
    static void Main()
    {
        // 定义一个整数数组
        var numbers = new[] { 12345 };
        
        // 计算所有数字的总和
        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[] { 123 };
        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(110);
        
        // 将序列分割成每三个元素一组
        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[] { 123456 };
        
        // 取出小于 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
        {
            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 { getset; }
        public int Age { getset; }
    }
}

六、GroupBy

GroupBy 方法根据指定的键选择器函数将序列中的元素分组。

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        // 创建一个人的列表
        var people = new List
        {
            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 { getset; }
        public int Age { getset; }
    }
}

七、ToDictionary

ToDictionary 方法根据指定的键选择器和元素选择器函数从序列创建字典。

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        // 创建一个人的列表
        var people = new List
        {
            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 { getset; }
        public int Age { getset; }
    }
}

八、SelectMany

SelectMany 方法将序列中的每个元素映射到一个 IEnumerable 并将结果序列扁平化为单一序列。

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        // 创建一个人的列表,每个人都有宠物列表
        var people = new List
        {
            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 { getset; }
        public List<string> Pets { getset; }
    }
}

九、Except

Except 方法产生两个序列之间的差集,即第一个序列中有但在第二个序列中没有的元素。

using System;
using System.Linq;

class Program
{
    static void Main()
    {
        // 创建两个整数数组
        var numbers1 = new[] { 12345 };
        var numbers2 = new[] { 34567 };
        
        // 获取第一个数组中不在第二个数组中的元素
        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[] { 123456 };
        
        // 根据是否为偶数将数组分成两部分
        var (evens, odds) = numbers.Partition(n => n % 2 == 0);
        
        // 打印偶数
        Console.WriteLine("Evens: " + string.Join(", ", evens));
        
        // 打印奇数
        Console.WriteLine("Odds: " + string.Join(", ", odds));
    }
}

结论

LINQ 是 .NET 生态系统中的一个强大工具,提供了大量用于查询和操作集合的方法。虽然有些方法被广泛知晓和使用,但其他方法如 AggregateZipChunkDistinctBy, 和 Partition 可以为各种编程场景提供独特而高效的解决方案。通过理解和利用这些被低估的 LINQ 方法,你可以写出更加简洁、可读性强且高效的代码。