【问题标题】:Generic Map/Reduce List Extensions in C#C# 中的通用 Map/Reduce 列表扩展
【发布时间】:2010-09-07 14:13:10
【问题描述】:

我正在编写一些扩展来模仿 Lisp 中的 map 和 reduce 函数。

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);
}

transform 函数将减少诸如:

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

这有意义吗?会不会更好?

【问题讨论】:

  • 这已经存在。看看 C# 3 / LINQ。
  • 是的,这是有道理的。这个问题和其他几个问题的答案显示了一个令人惊讶的缺乏对什么是reduce 函数的理解。是的,输出类型应该独立于输入类型。 Aggregate 不是一个 reduce 函数,正如许多人所声称的那样。也许这就是为什么他们称之为不同的东西。

标签: c# functional-programming extension-methods


【解决方案1】:

我会改用内置的 Func 委托。相同的代码适用于任何 IEnumerable。你的代码会变成:

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);
}

【讨论】:

    【解决方案2】:

    您可能想要添加一种方法来执行映射但返回一个新列表,而不是处理传入的列表(并且返回列表可以证明对链接其他操作很有用)......也许是一个带有指示是否要返回新列表的布尔值,例如:

    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;
    }
    

    【讨论】:

      【解决方案3】:

      这些看起来与 Linq 中的扩展非常相似:

      //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 */);
      

      为什么第二个例子叫Transform?您是否打算以某种方式更改列表中的值?如果是这种情况,您最好使用ConvertAll&lt;T&gt;Select&lt;T&gt;

      【讨论】:

      • C++ 标准库的std::transform 就是这样做的。这是link to std::transform
      • @RAM 我想这将是一个 C++ 等价于Select,但是 C++ 中的模板和 C# 中的泛型非常不同。另外这个OP询问函数式编程,因此扩展方法可以采用不可变集合并输出不可变集合。在 C++ 中,这将一个范围作为输入并改变第二个范围作为输出,这更像是一种 OO 方法。
      【解决方案4】:

      根据此链接Functional Programming in C# 3.0: How Map/Reduce/Filter can Rock your World,以下是 System.Linq 命名空间下 C# 中的等价物:

      【讨论】:

        【解决方案5】:

        我建议创建内部使用 LinQ like this 的扩展方法:

        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);
        }
        

        这里有一些示例用法:

        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

        【讨论】:

          猜你喜欢
          • 2016-02-27
          • 1970-01-01
          • 2023-02-05
          • 1970-01-01
          • 1970-01-01
          • 2012-02-19
          • 1970-01-01
          • 1970-01-01
          • 2015-10-02
          相关资源
          最近更新 更多