一直深入到 Map 和 Reduce 的基础知识。
Map 是一个函数,它将某种列表中的项目“转换”为另一种项目,然后将它们放回相同类型的列表中。
假设我有一个数字列表:[1,2,3] 并且我想将每个数字加倍,在这种情况下,“将每个数字加倍”的函数是函数 x = x * 2。并且没有映射,我可以写一个简单的循环,比如说
A = [1, 2, 3]
foreach (item in A) A[item] = A[item] * 2
我有 A = [2, 4, 6] 但不是写循环,如果我有一个 map 函数,我可以写
A = [1, 2, 3].Map(x => x * 2)
x => x * 2 是针对 [1,2,3] 中的元素执行的函数。发生的情况是程序获取每个项目,通过使 x 等于每个项目来对其执行 (x => x * 2),并生成结果列表。
1 : 1 => 1 * 2 : 2
2 : 2 => 2 * 2 : 4
3 : 3 => 3 * 2 : 6
所以在使用 (x => x * 2) 执行 map 函数后,您将拥有 [2, 4, 6]。
Reduce 是一个函数,它“收集”列表中的项目并对它们所有执行一些计算,从而将它们缩减为单个值。
求和或求平均值都是 reduce 函数的实例。例如,如果您有一个数字列表,例如 [7, 8, 9] 并且您希望将它们相加,您可以编写这样的循环
A = [7, 8, 9]
sum = 0
foreach (item in A) sum = sum + A[item]
但是,如果你可以访问 reduce 函数,你可以这样写
A = [7, 8, 9]
sum = A.reduce( 0, (x, y) => x + y )
现在有点令人困惑,为什么要传递 2 个参数(0 和带有 x 和 y 的函数)。为了使 reduce 函数有用,它必须能够获取 2 个项目,计算一些东西并将这 2 个项目“减少”为一个单一的值,因此程序可以减少每一对,直到我们有一个单一的值。
执行如下:
result = 0
7 : result = result + 7 = 0 + 7 = 7
8 : result = result + 8 = 7 + 8 = 15
9 : result = result + 9 = 15 + 9 = 24
但是您不想一直从零开始,所以第一个参数可以让您指定一个种子值,特别是第一行 result = 中的值。
假设你想对 2 个列表求和,它可能看起来像这样:
A = [7, 8, 9]
B = [1, 2, 3]
sum = 0
sum = A.reduce( sum, (x, y) => x + y )
sum = B.reduce( sum, (x, y) => x + y )
或您更可能在现实世界中找到的版本:
A = [7, 8, 9]
B = [1, 2, 3]
sum_func = (x, y) => x + y
sum = A.reduce( B.reduce( 0, sum_func ), sum_func )
这在数据库软件中是一件好事,因为有了 Map\Reduce 支持,您可以使用数据库,而无需知道数据如何存储在数据库中以使用它,这就是数据库引擎的用途。
您只需要能够通过向引擎提供 Map 或 Reduce 函数来“告诉”引擎您想要什么,然后 DB 引擎就可以找到处理数据的方法,应用您的函数并提出在您不知道它如何遍历所有记录的情况下获得您想要的所有结果。
有索引和键、连接和视图以及单个数据库可以保存的许多东西,因此通过保护您免受数据实际存储方式的影响,您的代码更易于编写和维护。
并行编程也是如此,如果您只指定要对数据执行的操作而不是实际实现循环代码,那么底层基础架构可以“并行化”并在同时并行循环中执行您的函数。