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>,有什么原因阿?
浙公网安备 33010602011771号