C#函数式编程风格-范型Filter,Map,Reduct函数的实现

早上看园友的一篇文章《lambda与闭包》,忽然间想起了以前刚学Python,刚接触FP时的高兴劲。对FP的no-side-effect的向往,对Declaration式编程的喜爱,让我对于编程,对于另一种程序设计的思想有了种转变。

还记得那时,看到Python中的built-in函数Filter,Map,Reduce,心想为什么.NET的BCL中怎么就没有呢。C#3.0出来以后,基本上已经可以DIY一个山寨版的Filter,Map,Reduce了,看代码:

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

namespace FuncPro
{
    class Program
    {
        static T[] Filter<T>(Func<T, bool> func, IEnumerable<T> iSource)
        {
            List<T> iResult = new List<T>();
            foreach (var item in iSource)
            {
                if (func(item))
                    iResult.Add(item);
            }
            return iResult.ToArray();
        }
        static T[] Map<T>(Func<T, T> func, IEnumerable<T> iSource)
        {
            List<T> iResult = new List<T>();
            foreach (var item in iSource)
            {
                iResult.Add(func(item));
            }

            return iResult.ToArray();
        }
        static T Reduce<T>(Func<T, T, T> func, IEnumerable<T> iSource)
        {
            T sum = default(T);
            foreach (var item in iSource)
            {
                sum = func(sum, item);
            }
            return sum;
        }

        static void PrintArray(int[] iSource)
        {
            Console.Write("\t");
            iSource.ToList().ForEach(x => Console.Write("{0} ", x));
            Console.WriteLine();
        }
        static void Indent(string msg)
        {
            Console.WriteLine("{0}:", msg);
        }


        static void Main(string[] args)
        {
            int[] iSource = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            Indent("Source");
            PrintArray(iSource);


            int[] iFilterResult = Filter(x => x > 5, iSource);
            Indent("Filter, item more than 5");
            PrintArray(iFilterResult);


            int[] iMapResult = Map(x => x * 2, iSource);
            Indent("Map, multiple with 2");
            PrintArray(iMapResult);


            int iReduceResult = Reduce((x, y) => x + y, iSource);
            Indent("Reduce");
            Console.Write("\t{0}\n ", iReduceResult);

            Console.ReadKey();
        }
    }
}

前些日子和一个朋友闲聊到.NET加入了很多函数式编程的元素,应该可以写出函数式编程风格的代码来,也应该算是支持函数式编程的语言了,今天随手写了代码感觉确实是这样了。

PS.

今天看《CLR via C# 3e》时看到Jefferey利用扩展方法(Extension Method)来提高代码可读性的例子,我将上面的代码重构了一下,以提高可读性:

static class ExtendMethod
{
    public static void ShowItems<T>(this IEnumerable<T> collection)
    {
        Console.Write("\t");
        collection.ToList().ForEach((x) => Console.Write("{0} ", x));
        Console.WriteLine();
    }
}
class Program
{
    static T[] Filter<T>(Func<T, bool> func, IEnumerable<T> iSource)
    {
        List<T> iResult = new List<T>();
        foreach (var item in iSource)
        {
            if (func(item))
                iResult.Add(item);
        }
        return iResult.ToArray();
    }
    static T[] Map<T>(Func<T, T> func, IEnumerable<T> iSource)
    {
        List<T> iResult = new List<T>();
        foreach (var item in iSource)
        {
            iResult.Add(func(item));
        }

        return iResult.ToArray();
    }
    static T Reduce<T>(Func<T, T, T> func, IEnumerable<T> iSource)
    {
        T sum = default(T);
        foreach (var item in iSource)
        {
            sum = func(sum, item);
        }
        return sum;
    }

    static void PrintArray(int[] iSource)
    {
        Console.Write("\t");
        iSource.ToList().ForEach(x => Console.Write("{0} ", x));
        Console.WriteLine();
    }
    static void Indent(string msg)
    {
        Console.WriteLine("{0}:", msg);
    }

    static void Main(string[] args)
    {
        int[] source = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        Indent("Source");
        source.ShowItems();


        int[] filterResult = Filter(x => x > 5, source);
        Indent("Filter, item more than 5");
        filterResult.ShowItems();


        int[] mapResult = Map(x => x * 2, source);
        Indent("Map, multiple with 2");
        mapResult.ShowItems();


        int reduceResult = Reduce((x, y) => x + y, source);
        Indent("Reduce");
        new[] { reduceResult }.ShowItems();

        Console.ReadKey();
    }
}
@ 2010-05-04 08:00

Comments:

Sharing your thoughts: