C#提高:函数式编程中常见的 `map`、`filter`、`reduce` 的类似操作-由Deepseek产生

在 C# 中,函数式编程中常见的 mapfilterreduce 操作可以通过 LINQ(Language Integrated Query) 方便地实现。它们分别对应以下方法:

函数式操作 C# LINQ 方法 说明
map Select 将序列中的每个元素映射为新形式
filter Where 根据条件筛选元素
reduce Aggregate 对序列进行累积计算(累加、累乘等)

下面给出一个完整的示例,演示如何对一个整数列表依次进行筛选(filter)、映射(map)和归约(reduce)。

csharp 复制代码
using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

        // filter: 保留偶数
        var filtered = numbers.Where(n => n % 2 == 0);
        // map: 每个数平方
        var mapped = filtered.Select(n => n * n);
        // reduce: 求和
        int result = mapped.Aggregate((acc, n) => acc + n);

        // 可以链式调用,一气呵成
        int result2 = numbers
                        .Where(n => n % 2 == 0)   // filter
                        .Select(n => n * n)       // map
                        .Aggregate((acc, n) => acc + n); // reduce

        Console.WriteLine($"结果: {result}");   // 输出 56 (4+16+36)
        Console.WriteLine($"链式结果: {result2}"); // 同样输出 56
    }
}

常用变体与说明

  • Select 可以投射出新的类型,例如 .Select(x => new { Name = x })
  • Where 可以串联使用,进一步细化筛选条件。
  • Aggregate 可以指定种子值,例如 Aggregate(0, (acc, n) => acc + n),等价于 Sum();但 Aggregate 更通用,可以实现累乘、拼接字符串等。
  • 如果只是简单的求和、求平均、求最大值等,可以使用专用方法 Sum()Average()Max()Min() 等,它们都是归约操作的简化版。

查询表达式语法(可选)

除了方法语法,C# 还提供了查询表达式语法,更接近 SQL:

csharp 复制代码
var result = (from n in numbers
              where n % 2 == 0
              select n * n).Sum();

这种方法在复杂查询时可读性更好,但归约操作通常仍需使用方法语法(如 Sum())。

总结

在 C# 中,利用 LINQ 可以轻松实现函数式编程中的核心操作,且代码简洁、类型安全。以上示例展示了 mapfilterreduce 的对应实现,实际开发中可根据需求组合使用。

当然可以。不使用 LINQ,我们完全可以通过普通循环委托 手动实现类似 mapfilterreduce 的功能。下面提供两种常见的实现方式:直接使用循环 ,或自定义扩展方法 (无需 System.Linq 命名空间)。


1. 直接使用循环

最原始的方式就是显式编写 foreachfor 循环,依次进行筛选、转换和累积。

csharp 复制代码
using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

        // filter: 保留偶数
        List<int> filtered = new List<int>();
        foreach (var n in numbers)
        {
            if (n % 2 == 0)
                filtered.Add(n);
        }

        // map: 每个数平方
        List<int> mapped = new List<int>();
        foreach (var n in filtered)
        {
            mapped.Add(n * n);
        }

        // reduce: 求和
        int result = 0;
        foreach (var n in mapped)
        {
            result += n;
        }

        Console.WriteLine(result); // 56
    }
}

这种方式直观,但代码冗长,且每一步都要创建中间集合,不适合大型数据流。


2. 自定义扩展方法(模拟 LINQ 风格)

我们可以自己实现类似 SelectWhereAggregate 的扩展方法,完全脱离 System.Linq。这些方法内部仍然使用循环,但提供了链式调用的优雅语法。

csharp 复制代码
using System;
using System.Collections.Generic;

public static class MyLinqExtensions
{
    // 模拟 Select (map)
    public static IEnumerable<TResult> MySelect<TSource, TResult>(
        this IEnumerable<TSource> source,
        Func<TSource, TResult> selector)
    {
        foreach (var item in source)
        {
            yield return selector(item);
        }
    }

    // 模拟 Where (filter)
    public static IEnumerable<TSource> MyWhere<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate)
    {
        foreach (var item in source)
        {
            if (predicate(item))
                yield return item;
        }
    }

    // 模拟 Aggregate (reduce)
    public static TAccumulate MyAggregate<TSource, TAccumulate>(
        this IEnumerable<TSource> source,
        TAccumulate seed,
        Func<TAccumulate, TSource, TAccumulate> func)
    {
        TAccumulate result = seed;
        foreach (var item in source)
        {
            result = func(result, item);
        }
        return result;
    }
}

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

        int result = numbers
                        .MyWhere(n => n % 2 == 0)   // filter
                        .MySelect(n => n * n)       // map
                        .MyAggregate(0, (acc, n) => acc + n); // reduce

        Console.WriteLine(result); // 56
    }
}

关键点

  • 使用 yield return 实现延迟执行(流式处理),避免中间集合。
  • Func 委托让调用者自定义逻辑。
  • 这些方法本质上就是 LINQ 内部实现方式的简化版,但完全不需要引用 System.Linq 命名空间。

3. 使用普通静态方法(不依赖扩展方法)

如果不喜欢扩展方法,也可以直接写静态方法,手动传入集合和委托:

csharp 复制代码
public static class MyFunctions
{
    public static IEnumerable<T> Filter<T>(IEnumerable<T> source, Func<T, bool> predicate)
    {
        foreach (var item in source)
            if (predicate(item))
                yield return item;
    }

    public static IEnumerable<TResult> Map<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, TResult> mapper)
    {
        foreach (var item in source)
            yield return mapper(item);
    }

    public static TAccumulate Reduce<TSource, TAccumulate>(IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> reducer)
    {
        TAccumulate result = seed;
        foreach (var item in source)
            result = reducer(result, item);
        return result;
    }
}

// 使用
var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
var filtered = MyFunctions.Filter(numbers, n => n % 2 == 0);
var mapped = MyFunctions.Map(filtered, n => n * n);
int sum = MyFunctions.Reduce(mapped, 0, (acc, n) => acc + n);
Console.WriteLine(sum); // 56

总结

  • 不使用 LINQ 时,可以通过循环 + 委托完全实现 mapfilterreduce
  • 自定义扩展方法可以保留链式调用的优雅性,且不依赖 System.Linq
  • 手动实现的好处是更清晰地理解内部机制,且在某些受限环境(如不允许引用 LINQ 的程序集)中仍然可用。

实际开发中,如果项目允许,推荐直接使用 LINQ,因为它更简洁、可读性更高且经过了高度优化。但在需要精确控制或学习原理时,自己实现也是很好的练习。

相关推荐
格林威2 小时前
Baumer相机金属冲压件毛刺高度测量:量化去毛刺效果的 5 个核心方法,附 OpenCV+Halcon 实战代码!
人工智能·opencv·计算机视觉·c#·视觉检测·机器视觉·工业相机
张人玉16 小时前
C#通讯(上位机)常用知识点
开发语言·c#·通讯·上位机开发
武藤一雄19 小时前
C#:nameof 运算符全指南
开发语言·microsoft·c#·.net·.netcore
CSharp精选营20 小时前
聊一聊 C# 中的闭包陷阱:foreach 循环的坑你还记得吗?
c#·foreach·循环·for循环
月巴月巴白勺合鸟月半21 小时前
FHIR 的使用
人工智能·c#·fhir
公子小六21 小时前
基于.NET的Windows窗体编程之WinForms控件简介
windows·microsoft·c#·.net
观无1 天前
mysql5.7下载地址
c#
武藤一雄1 天前
C# 核心技术解析:Parse vs TryParse 实战指南
开发语言·windows·microsoft·微软·c#·.netcore
代数狂人1 天前
在Godot中应用面向对象原则:C#脚本实践
c#·游戏引擎·godot