什么是Map/Reduce
维基百科中的解释:
MapReduce is a programming model and an associated implementation for processing and generating big data sets with a parallel, distributed algorithm on a cluster.
它是一种编程模型和相关的实现,用于在集群上使用并行分布式算法来处理和生成大数据集。
map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。
reduce把一个函数作用在一个序列上, 并把结果继续和序列的下一个元素做累积计算。
Python3中的Map/Reduce
Map
| 12
 3
 4
 
 | l = [2, 3, 4]l = list(map(lambda x: x * 2, l))
 print(l)
 
 
 | 
将列表中的每个元素都乘以2. 
Map接受两个参数。
第一个参数是一个函数。这个函数接受一个参数,它就是迭代的元素。
第二个参数是被迭代的序列。
注意:在Python2中返回的是list, 而在Python3中返回的是一个map object.
Reduce
| 12
 3
 4
 5
 
 | import functoolsl = [2, 3, 4]
 sum = functools.reduce(lambda prev, curr: prev + curr * 2, l, 0)
 print(sum)
 
 
 | 
将列表中的每个元素乘以2再累加求和。
再来一个稍微更复杂的例子。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | import functools
 def reduce_func(prev, curr):
 prev[curr["name"]] = curr["age"]
 return prev
 
 l = [
 { "name": "A", "age": 12 },
 { "name": "B", "age": 20 },
 { "name": "C", "age": 16 },
 { "name": "D", "age": 30 },
 { "name": "E", "age": 56 },
 ]
 
 result = functools.reduce(reduce_func, l, {})
 print(result)
 
 
 | 
Reduce接受三个参数。
第一个参数是一个函数。这个函数接受两个参数,第一个是上一个累加的值,第二个是当前迭代的元素。
第二个参数是被迭代的序列。
第三个参数是初始累加值。
JavaScript中的Map/Reduce
用法和Python中的大同小异。
Map
| 12
 3
 4
 
 | let l = [2, 3, 4]l = l.map( x => x * 2)
 console.log(l)
 
 
 | 
更详细的介绍参考MDN.
Reduce
| 12
 3
 4
 
 | let l = [2, 3, 4]result = l.reduce((prev, curr) => prev + curr, 0)
 console.log(result)
 
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | let l = [{ "name": "A", "age": 12 },
 { "name": "B", "age": 20 },
 { "name": "C", "age": 16 },
 { "name": "D", "age": 30 },
 { "name": "E", "age": 56 },
 ];
 
 let result = l.reduce( (prev, curr) => { prev[curr.name] = curr.age; return prev;}, {} );
 console.log(result);
 
 
 | 
更详细的介绍参考MDN.
注意:若JS解析引擎使用的是es6之前的标准,可用lodash替代。
C++中的Map/Reduce
Map
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | #include <iostream>#include <vector>
 #include <algorithm>
 
 int main(int argc, char *argv[])
 {
 std::vector<int> v{2, 3, 4};
 std::transform(v.begin(), v.end(), v.begin(), [](int i) { return i * 2; });
 std::for_each(v.begin(), v.end(), [](int i) { std::cout << i << std::endl; });
 return 0;
 }
 
 
 
 
 | 
上面这种方式会直接修改原序列。
如果我们不期望修改原序列,应该这样 :
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | #include <iostream>#include <vector>
 #include <algorithm>
 #include <iterator>
 
 int main(int argc, char *argv[])
 {
 std::vector<int> v{2, 3, 4};
 std::vector<int> ordinals;
 std::transform(v.begin(), v.end(), std::back_inserter(ordinals), [](int i) { return i * 2; });
 std::for_each(ordinals.begin(), ordinals.end(), [](int i) { std::cout << i << std::endl; });
 return 0;
 }
 
 | 
Reduce
直到C++17标准,才加入了std::reduce.
一个简单的替代实现:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | #include <iostream>#include <vector>
 #include <algorithm>
 #include <iterator>
 #include <functional>
 
 template <typename T>
 T reduce(const std::vector<T>& data,
 const std::function<T(T,T)>& reduceFn) {
 typedef typename std::vector<T>::const_iterator Iterator;
 Iterator it = data.cbegin();
 Iterator end = data.cend();
 if (it == end) {
 throw 0;
 } else {
 T accumulator = *it;
 ++it;
 for (; it != end; ++it) {
 accumulator = reduceFn(accumulator, *it);
 }
 return accumulator;
 }
 }
 
 int main(int argc, char *argv[])
 {
 std::vector<int> v{2, 3, 4};
 int result = reduce<int>(v, [](int prev, int curr){ return prev + curr; });
 std::cout << result << std::endl;
 return 0;
 }
 
 | 
Reference