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,因为它更简洁、可读性更高且经过了高度优化。但在需要精确控制或学习原理时,自己实现也是很好的练习。

相关推荐
棉晗榜11 分钟前
C# HttpClient配置具有tls指纹发起跟浏览器一样的请求解决反爬虫防护
开发语言·爬虫·c#
吴可可12327 分钟前
在CAD中点击添加多段线顶点的方法与实现
c#
全栈小51 小时前
【C#】.net core,静态方法线程安全解析,面试时经常被问的线程安全就藏在里面
安全·c#·.netcore
天下无敌笨笨熊2 小时前
C#视频开发心得
开发语言·c#·音视频
LccKyI2 小时前
C#基础编程 面试题汇总(三)
笔记·c#
半亩码田4 小时前
C#转Python第4.1篇:当 try-catch 遇上 try-except:异常处理的大不同
开发语言·python·c#
z落落5 小时前
C# Modbus-RTU 串口读写设备+CRC16+邮件告警
开发语言·c#
DS随心转小程序5 小时前
Gemini只能导出了一部分Word文档,很少的一部分,不是我这个窗口所有的对话内容?
开发语言·人工智能·c#·word·豆包·deepseek·ai导出鸭
格林威5 小时前
C# 相机图像配合频闪光源:实现高速稳定拍摄的几个方法
开发语言·网络·人工智能·数码相机·计算机视觉·c#·视觉检测
CSDN_RTKLIB5 小时前
CAD绘图单位
c#