Appearance
Map/Reduce
If you've read Google's famous paper "MapReduce: Simplified Data Processing on Large Clusters," you will have a general understanding of the concept of map/reduce.
Map
For example, if we have a function :
and we want to apply this function to an array [1, 2, 3, 4, 5, 6, 7, 8, 9]
, we can use map as follows:
javascript
f(x) = x * x
│
│
┌───┬───┬───┬───┼───┬───┬───┬───┐
│ │ │ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
[ 1 2 3 4 5 6 7 8 9 ]
│ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
[ 1 4 9 16 25 36 49 64 81 ]
Since the map()
method is defined in JavaScript's Array, we call the Array's map()
method and pass our own function to get a new Array as a result:
javascript
function pow(x) {
return x * x;
}
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let results = arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]
console.log(results);
Note: The argument passed to map()
is pow
, which is the function object itself.
You might think that we don't need map()
, as we can write a loop to calculate the result:
javascript
let f = function (x) {
return x * x;
};
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let result = [];
for (let i = 0; i < arr.length; i++) {
result.push(f(arr[i]));
}
This is indeed possible, but from the loop code above, we cannot immediately see "apply f(x)
to each element of the Array and generate a new Array of results."
Thus, map()
, as a higher-order function, abstracts the operation rules, allowing us not only to compute simple
but also to calculate any complex function, for example, converting all numbers in an Array to strings:
javascript
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']
Just one line of code.
Reduce
Now let's look at how reduce
works. The reduce()
method on an Array applies a function to the Array's ([x1, x2, x3...]). This function must take two parameters; reduce()
continues accumulating the result with the next element in the sequence, effectively performing:
For instance, to sum an Array, we can use reduce
as follows:
javascript
let arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x + y;
}); // 25
If the array has only one element, an additional initial parameter is needed to ensure there are at least two:
javascript
let arr = [123];
arr.reduce(function (x, y) {
return x + y;
}, 0); // 123
Exercise: Use reduce()
to calculate the product:
javascript
function product(arr) {
// FIXME:
return 0;
}
// Test:
if (product([1, 2, 3, 4]) === 24 && product([0, 1, 2]) === 0 && product([99, 88, 77, 66]) === 44274384) {
console.log('Test passed!');
}
else {
console.log('Test failed!');
}
To transform [1, 3, 5, 7, 9]
into the integer 13579
, reduce()
can also be useful:
javascript
let arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x * 10 + y;
}); // 13579
If we continue to improve this example, we can figure out how to convert a string 13579
into an Array—[1, 3, 5, 7, 9]
—and then use reduce()
to write a function that converts a string to a Number.
Exercise: Without using JavaScript's built-in parseInt()
function, implement a string2int()
function using map
and reduce
:
javascript
function string2int(s) {
// FIXME:
return 0;
}
// Test:
if (string2int('0') === 0 && string2int('12345') === 12345 && string2int('12300') === 12300) {
if (string2int.toString().indexOf('parseInt') !== -1) {
console.log('Do not use parseInt()!');
} else if (string2int.toString().indexOf('Number') !== -1) {
console.log('Do not use Number()!');
} else {
console.log('Test passed!');
}
}
else {
console.log('Test failed!');
}
Exercise
Please normalize user input of improperly formatted English names to capitalized first letters and lowercase for the rest. Input: ['adam', 'LISA', 'barT']
, Output: ['Adam', 'Lisa', 'Bart']
.
javascript
function normalize(arr) {
// FIXME:
return [];
}
// Test:
if (normalize(['adam', 'LISA', 'barT']).toString() === ['Adam', 'Lisa', 'Bart'].toString()) {
console.log('Test passed!');
}
else {
console.log('Test failed!');
}
Little Ming hopes to use map()
to convert strings to integers, and his code is quite concise:
javascript
let arr = ['1', '2', '3'];
let r;
r = arr.map(parseInt);
console.log(r);
However, the result is 1, NaN, NaN
. Little Ming is puzzled. Please help him find the reason and correct the code.
Hint: Refer to the documentation for Array.prototype.map().