JavaScript Jems - Functional Iteration |
Written by Mike James | |||||||||||||||||||||||||||||||||||||||
Monday, 08 June 2020 | |||||||||||||||||||||||||||||||||||||||
Page 2 of 2
ReduceThe second most well known function of this kind is probably reduce. This doesn't just take each element in turn and modify it, it also keeps a running sum. The reduce method really does reduce an array to a single result. The function that you pass to it has four parameters – the accumulator for the running sum, the current element, the index and the entire array. You also have to optionally pass an initial value for the accumulator and although optional, in practice it is usually essential. For example, to sum the elements of an Array you would use: const myArray = [1, 2, 3, 4, 5, 6]; const sum = myArray.reduce(function (acc, element) { return element + acc; } ,0); console.log(sum); The initial value of the accumulator is set to zero and then each element is added to it in turn. The call to reduce is equivalent to: let acc=0; for(const element of myArray){ acc = element + acc; } Notice that reduce in its simplest form is different from the other array methods that "hide" a for loop because it really does reduce an array to a single value. However, it doesn't have to. The power of "everything is an object" means that reduce can be used in ways that don't reduce anything. For example: const myArray = [1, 2, 3, 4, 5, 6]; const mycopy = myArray.reduce(function (acc, element) { acc.push(element); return acc; } ,[]); console.log(mycopy); Notice that the accumulator, acc, is initialized to a null array. This means that you can use it as an array in the update function and, for example, call its push method which adds the element to the end of the array. The result is a complete copy of the array rather than anything reduced. You can see that it is possible to use reduce to do any of the jobs that map can do. Once you allow everything to be an object you do open up this sort of possibility. A very common idiom is to chain this sort of method together in a fluent style. For example: function square(x){ return x*x; } function sum(x,y){ return x+y; } const myArray = [1, 2, 3, 4, 5, 6]; console.log(myArray.map(square).reduce(sum)); computes the sum of squares of myArray. Notice, however, that this only works because map returns an Array that you can call reduce on and this involves two complete passes through the Array whereas an explicit for loop, or even forEach, would have done the job in one pass. This is inefficient and when you add it to the fact that map and reduce are generally slower than for loops, you can see that there is a cost to be paid for the clarity of expression. One of the reasons for map/reduce to be a preferred way of writing advanced code is that they lend themselves to being computed on a parallel computer. The map can be split up between different processors each working on a different part of the array and the reduce can be computed in the same way, but with the different processors passing their results to a single collecting processor. This is the basis of parallel systems such as Hadoop, but there are no such advantages for JavaScript. There are lots of similar array methods and you can look them up in the documentation, but here is a list and brief description accurate at the time of writing:
There are also methods that involve partial scanning of the array, but these are the classic "hide the for loop" methods. In remander of the chapter but not included in this extract:
Now available as a book from your local Amazon.JavaScript Jems:
|
|||||||||||||||||||||||||||||||||||||||
Last Updated ( Monday, 08 June 2020 ) |