关于函数式编程:C#中的通用映射/减少列表扩展

关于函数式编程:C#中的通用映射/减少列表扩展

Generic Map/Reduce List Extensions in C#

我正在编写一些扩展程序来模仿地图并简化Lisp中的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public delegate R ReduceFunction<T,R>(T t, R previous);
public delegate void TransformFunction< T >(T t, params object[] args);

public static R Reduce<T,R>(this List< T > list, ReduceFunction<T,R> r, R initial)
{
     var aggregate = initial;
     foreach(var t in list)
         aggregate = r(t,aggregate);

     return aggregate;
}
public static void Transform< T >(this List< T > list, TransformFunction< T > f, params object [] args)
{
    foreach(var t in list)
         f(t,args);
}

转换功能将减少残骸,例如:

1
2
3
foreach(var t in list)
    if(conditions && moreconditions)
        //do work etc

这有意义吗? 会更好吗?


根据此链接,《 C#3.0中的函数编程》:Map / Reduce / Filter如何影响您的世界,以下是System.Linq命名空间下C#中的等效项:

  • 贴图-> Enumerable.Select
  • 减少-> Enumerable.Aggregate
  • 过滤器->可枚举。

这些看起来已经非常类似于Linq中的扩展:

1
2
3
4
5
6
7
8
//takes a function that matches the Func<T,R> delegate
listInstance.Aggregate(
    startingValue,
    (x, y) => /* aggregate two subsequent values */ );

//takes a function that matches the Action< T > delegate
listInstance.ForEach(
    x => /* do something with x */);

为什么第二个示例称为"变换"?您打算以某种方式更改列表中的值吗?如果是这种情况,最好使用ConvertAll< T >Select< T >


我会改用内置的Func委托。相同的代码可在任何IEnumerable上使用。您的代码将变成:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static R Reduce<T,R>(this IEnumerable< T > list, Func<T,R> r, R initial)
{
     var aggregate = initial;
     foreach(var t in list)
         aggregate = r(t,aggregate);

     return aggregate;
}
public static void Transform< T >(this IEnumerable< T > list, Func< T > f)
{
    foreach(var t in list)
             f(t);
}

我建议创建内部使用LinQ的扩展方法,如下所示:

1
2
3
4
5
6
7
8
9
10
11
public static IEnumerable<R> Map<T, R>(this IEnumerable< T > self, Func<T, R> selector) {
    return self.Select(selector);
}

public static T Reduce< T >(this IEnumerable< T > self, Func<T, T, T> func) {
    return self.Aggregate(func);
}

public static IEnumerable< T > Filter< T >(this IEnumerable< T > self, Func<T, bool> predicate) {
    return self.Where(predicate);
}

下面是一些用法示例:

1
2
3
4
5
IEnumerable<string> myStrings = new List<string>() {"1","2","3","4","5" };
IEnumerable<int> convertedToInts = myStrings.Map(s => int.Parse(s));
IEnumerable<int> filteredInts = convertedToInts.Filter(i => i <= 3); // Keep 1,2,3
int sumOfAllInts = filteredInts.Reduce((sum, i) => sum + i); // Sum up all ints
Assert.Equal(6, sumOfAllInts); // 1+2+3 is 6

(有关更多示例,请参见https://github.com/cs-util-com/cscore#ienumerable-extensions)


您可能想添加一种做映射的方法,但是返回一个新列表,而不是处理传入的列表(返回列表可以证明对链接其他操作很有用)...也许是带有布尔值的重载版本,它指示如果您想返回一个新列表,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static List< T > Transform< T >(this List< T > list, TransformFunction< T > f,
        params object [] args)
{
    return Transform(list, f, false, args);
}

public static List< T > Transform< T >(this List< T > list, TransformFunction< T > f,
        bool create, params object [] args)
{
    // Add code to create if create is true (sorry,
    // too lazy to actually code this up)
    foreach(var t in list)
         f(t,args);
    return list;
}


推荐阅读