Map 是一个函数,它将另一个函数应用于列表中的所有项目,以生成另一个列表,其中包含所有返回值。 (“将 f 应用于 x”的另一种说法是“调用 f,将其传递给 x”。所以有时说“应用”而不是“调用”听起来更好。)
这可能是用 C# 编写 map 的方式(它被称为 Select 并且在标准库中):
public static IEnumerable<R> Select<T, R>(this IEnumerable<T> list, Func<T, R> func)
{
foreach (T item in list)
yield return func(item);
}
由于您是 Java 小伙子,而 Joel Spolsky 喜欢向 GROSSLY UNFAIR LIES 讲述 Java 是多么糟糕(实际上,他没有撒谎,这很糟糕,但我想赢得您的支持),这是我的Java版本的粗略尝试(我没有Java编译器,我隐约记得Java版本1.1!):
// represents a function that takes one arg and returns a result
public interface IFunctor
{
object invoke(object arg);
}
public static object[] map(object[] list, IFunctor func)
{
object[] returnValues = new object[list.length];
for (int n = 0; n < list.length; n++)
returnValues[n] = func.invoke(list[n]);
return returnValues;
}
我相信这可以通过一百万种方式进行改进。但这是基本思想。
Reduce 是一个将列表中的所有项目转换为单个值的函数。为此,需要为其提供另一个函数func,它将两个项目转换为一个值。它可以通过将前两项提供给func 来工作。然后是第三项的结果。然后是第四个项目的结果,依此类推,直到所有项目都消失了,我们只剩下一个值。
在 C# 中,reduce 被称为 Aggregate,并且再次出现在标准库中。我将直接跳到 Java 版本:
// represents a function that takes two args and returns a result
public interface IBinaryFunctor
{
object invoke(object arg1, object arg2);
}
public static object reduce(object[] list, IBinaryFunctor func)
{
if (list.length == 0)
return null; // or throw something?
if (list.length == 1)
return list[0]; // just return the only item
object returnValue = func.invoke(list[0], list[1]);
for (int n = 1; n < list.length; n++)
returnValue = func.invoke(returnValue, list[n]);
return returnValue;
}
这些 Java 版本需要添加泛型,但我不知道如何在 Java 中做到这一点。但是您应该能够将匿名内部类传递给它们以提供函子:
string[] names = getLotsOfNames();
string commaSeparatedNames = (string)reduce(names,
new IBinaryFunctor {
public object invoke(object arg1, object arg2)
{ return ((string)arg1) + ", " + ((string)arg2); }
}
希望泛型能够摆脱强制转换。 C# 中的类型安全等效项是:
string commaSeparatedNames = names.Aggregate((a, b) => a + ", " + b);
为什么这很“酷”?将较大的计算分解为较小的部分的简单方法,以便它们可以以不同的方式重新组合在一起,总是很酷。 Google 将这一想法应用于并行化,因为 map 和 reduce 都可以在多台计算机上共享。
但关键要求不是您的语言可以将函数视为值。任何 OO 语言都可以做到这一点。并行化的实际要求是传递给 map 和 reduce 的小 func 函数不得使用或更新任何状态。它们必须返回一个仅依赖于传递给它们的参数的值。否则,当您尝试并行运行整个事情时,结果将完全搞砸。