Using filter.map.reduce in .net 2.0

众所周知,在Functional Programming的世界里,和lambda息息相关的三大函数是 filter, map, reduce.

C#语言作为一种多范式的编程语言自然支持这些特性,和python一样C#中也有三大函数在FCL中的实现,他们就是当当当 Where, Select, Aggregate, 而他们所对应的基本范型参数签名分别是Func<T, bool> , Func<T, T> , Func<T, T, T>。问题是在.net 3.5之后才有Func<>这个通用代理,那在2.0里,我们怎么办呢?很简单我们自己实现。

1. filter

filter接收一个表达式,从而筛选出集合中符合条件的元素,因此我们来创建这样的delegate

        delegate TResult FilterFunc<T, TResult>(T args);

filter的第二个参数就是该集合,我们用IEnumerable<T> 来表示,为了实现laziness我们还需要yield return 的配合,实现如下

        static IEnumerable<T> Filter<T>(FilterFunc<T, bool> fn, IEnumerable<T>  list)
        {
            foreach(T item in list)
                if(fn(item))
                    yield return item;
        }

2. map

map同样接受一个表达式,从而对集合中的元素进行transform。类似地,map中我们需要和filter一样的delegate

        delegate TResult MapFunc<T, TResult>(T args);

实现同样要有laziness

        static IEnumerable<T> Map<T>(MapFunc<T, T> fn, IEnumerable<T> list)
        {
            foreach (T item in list)
                yield return fn(item);
        }

3. reduce

reduce是一个对集合所有元素迭代的过程,他在aggregate的过程中需要2个输入参数,delegate如下

        delegate TResult ReduceFunc<T1, T2, TResult>(T1 args1, T2 args2);

这里实现的reduce是没有初始值的,所以如果集合只有一个元素就返回该元素,具体实现如下

        static T Reduce<T>(ReduceFunc<T, T, T> fn, IEnumerable<T> list)
        {
            IEnumerator<T> numerator = list.GetEnumerator();
            T result;
            if(numerator.MoveNext())
                result = numerator.Current;
            else
                return default(T);

            while (numerator.MoveNext())
                result = fn(result, numerator.Current);

            return result;
        }

4. 调用

filter/map因为都是延时求值的,所以用Print方法输出产生的结果集合。

    class Program
    {
        static void Main(string[] args)
        {
            List<string> list = new List<string>() { "China", "USA", "UK", "Russia" };
            var list1 = Filter<string>(s => s.Length >= 5, list);
            Print(list1);
            var list2 = Map<string>(s => string.Format("{0}" + s + "{1}", "<Element>", "</Element>"), list);
            Print(list2);
            string str = Reduce<string>((s1, s2) => s1 + ',' + s2, list);

            List<int> numlist = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            var numlist1 = Filter<int>(i => i % 3 == 0, numlist);
            Print(numlist1);
            var numlist2 = Map<int>(i => i * 2, numlist);
            Print(numlist2);
            int num = Reduce<int>((i, j) => i + j, numlist);

            Console.Read();
        }

        static void Print(System.Collections.IEnumerable list)
        {
            foreach (var item in list)
                Console.WriteLine(item);
        }
    }

5. 问题

不知道为什么在.net 2.0里就有了Action<T>, Predicate<T>,而直到3.5才有 Func<T>?

在Where的实现中为什么不用Predicate<T>, 而是用Func<T, bool>,有什么原因阿?

posted @ 2011-06-28 18:12  芥末丝张  阅读(344)  评论(0)    收藏  举报