C# 中的通用映射/归约列表扩展
-
09-06-2019 - |
题
我正在编写一些扩展来模仿 Lisp 中的映射和归约函数。
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);
}
变换函数会减少一些麻烦,例如:
foreach(var t in list)
if(conditions && moreconditions)
//do work etc
这有道理吗?还能更好吗?
解决方案
这些看起来已经与 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<T>
或者 Select<T>
.
其他提示
根据这个链接 C# 3.0 中的函数式编程:Map/Reduce/Filter 如何震撼您的世界 以下是 C# 中 System.Linq 命名空间下的等效项:
我会使用内置的 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);
}
您可能想要添加一种方法来执行映射但返回一个新列表,而不是处理传入的列表(并且返回列表对于链接其他操作可能有用)...也许是一个带有布尔值的重载版本,指示您是否要返回新列表,如下所示:
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;
}
我建议创建内部使用 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);
}
这里有一些示例用法:
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 欲了解更多示例)
不隶属于 StackOverflow