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

在 C# 中,函数式编程中常见的 map、filter、reduce 操作可以通过 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 可以轻松实现函数式编程中的核心操作,且代码简洁、类型安全。以上示例展示了 map、filter、reduce 的对应实现,实际开发中可根据需求组合使用。

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


1. 直接使用循环

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

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 风格)

我们可以自己实现类似 Select、Where、Aggregate 的扩展方法,完全脱离 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 时,可以通过循环 + 委托完全实现 map、filter、reduce。
  • 自定义扩展方法可以保留链式调用的优雅性,且不依赖 System.Linq。
  • 手动实现的好处是更清晰地理解内部机制,且在某些受限环境(如不允许引用 LINQ 的程序集)中仍然可用。

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

相关推荐
泛凡(Linyongui)1 小时前
基于 CW32L010 的智能厨卫调温旋钮方案--低成本 EC21 编码旋钮全解析
单片机·嵌入式硬件·c#
暴走约伯3 小时前
【VFX工具链源码拆解 02】告别机械劳动(上):一键统改百个子粒子颜色与批量重命名
3d·unity·c#·材质
信息安全失业大专人员5 小时前
每日了解一个智能体-WorkBuddy
开发语言·ai·c#·智能体
呆呆敲代码的小Y5 小时前
【实战精选面试题】C# 面试题详细解答,按难易程度排序
android·java·游戏·c#·游戏开发·unity面试题·c#面试题
淡海水6 小时前
09-01-内存-Unity资源生命周期全景
unity·c#·游戏引擎·.netcore·gc
椒颜皮皮虾྅9 小时前
让 C# 读懂整张图:DeploySharp 驱动 PaddleOCR v4/v5/v6,打通 OCR 全流程
开发语言·人工智能·深度学习·学习·c#·ocr·cuda
昂好的day9 小时前
C# 同步异步与多线程:Thread / Task / 线程池一次讲透(上篇)
开发语言·windows·c#
吃一碗粉只付一碗钱18 小时前
12-给SPA友好的401和403响应
c#·状态模式
caimouse1 天前
MonoDevelop 编译用户应用程序时调用的是哪个编译器
c#
will_net1 天前
apollo 站点部署&C#接入
开发语言·c#·apollo