C# 中的通用 Map/Reduce 列表扩展

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40075/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 09:48:09  来源:igfitidea点击:

Generic Map/Reduce List Extensions in C#

提问by Ben McNiel

I am writing a few extensions to mimic the map and reduce functions in Lisp.

我正在编写一些扩展来模拟 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);
}

The transform function will cut down on cruft like:

变换函数将减少像这样的 cruft:

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

Does this make sense? Could it be better?

这有意义吗?可以更好吗?

采纳答案by Keith

These look very similar to extensions in Linq already:

这些看起来与 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 */);

Why is the 2nd example called Transform? Do you intend to change the values in the list somehow? If that's the case you may be better off using ConvertAll<T>or Select<T>.

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

回答by Jake Pearson

I would use the built in Func delegates instead. This same code would work on any IEnumerable. Your code would turn into:

我会改用内置的 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);
}

回答by Mike Stone

You might want to add a way to do a map but return a new list, instead of working on the list passed in (and returning the list can prove useful to chain other operations)... perhaps an overloaded version with a boolean that indicates if you want to return a new list or not, as such:

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

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

回答by Ray

According to this link Functional Programming in C# 3.0: How Map/Reduce/Filter can Rock your Worldthe following are the equivalent in C# under the System.Linq namespace:

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

回答by CsUtil.com

I would recommend to create extension methods that internally use LinQ like this:

我建议创建像这样在内部使用 LinQ 的扩展方法:

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

Here some example usages:

这里有一些示例用法:

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

(See https://github.com/cs-util-com/cscore#ienumerable-extensionsfor more examples)

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