phizzy
phizzy

Reputation: 956

Why does the callback function for reduce take four parameters?

In studying the reduce method I'm not quite sure why the callback passed in needs the third and fourth parameters, index and array. In the example from the MDN:

[0, 1, 2, 3, 4].reduce(function(previousValue, currentValue, index, array) {
  return previousValue + currentValue;
});

A lot of other uses for the array reduce method or underscore reduce function I've studied only make use of the first two parameters for the callback: previousValue (sometimes seen as accumulator) and currentValue (aka elem, the value of the current index).

Why is reduce sometimes written with callback taking four parameters and sometimes written with only previousValue and currentValue?

What would be a case where the index and array parameters are needed?

Should all four parameters always be given in a function definition for reduce in case an application of reduce requires the third or fourth parameters?

Upvotes: 2

Views: 2204

Answers (3)

Tarik
Tarik

Reputation: 1

Another example, which I saw on an Exercism problem, and is a bit less contrived:

[...`${number}`].reduce((sum, digit, _, array) => sum + digit ** array.length, 0)

The exercise was to write a function that checks if a given number is an Armstrong Number, and the formula to figure that out uses the length of the array (i.e. the number of digits of the number). Plus it had this really concise way of writing it using deconstruction assignment, I think this is a great example of using those extra parameters neatly.

[...`${number}`].reduce((sum, digit, _, { length }) => sum + digit ** length, 0)

Upvotes: 0

dandavis
dandavis

Reputation: 16726

here is a (slightly) less-contrived example to sum up unique values in an array, skipping duplicates, using the index and array arguments to find unique values:

[0, 1, 2, 3, 2, 1, 0].reduce(function(previousValue, currentValue, index, array) {
  return array.indexOf(currentValue) === index ? // value used already?
         previousValue + currentValue :  // not used yet, add to sum
         previousValue; // used already, skip currentValue
}); // == 6  ( 0+1+2+3 )

live demo: http://pagedemos.com/fn764n659ama/1/

side note: [].reduce() runs quite a bit faster in V8 by specifying all four arguments as formal parameters on the callback, regardless of if they are used by the code inside the function.

Upvotes: 2

Peter Olson
Peter Olson

Reputation: 142947

If you only need to use the first two parameters, it is perfectly fine to leave the last two out in the function arguments list. In that case the last two arguments will just be ignored. To sum the array, this is a perfectly acceptable way to do it:

[0, 1, 2, 3, 4].reduce(function(previousValue, currentValue) {
  return previousValue + currentValue;
});

The last two parameters, index and array just give you extra information in case you need it. For example, say you wanted to sum up the all the elements in the array multiplied by their mirror element, that is, given the array [0, 1, 2, 3, 4] you wanted to output

(0 * 4) + (1 * 3) + (2 * 2) + (3 * 1) + (4 * 0)

then you would have to use the last two parameters:

[0, 1, 2, 3, 4].reduce(function(previousValue, currentValue, index, array) {
  return previousValue + currentValue * array[array.length - index - 1];
});

Admittedly, this is a somewhat contrived example, but I'm having a hard time coming up with an example that doesn't seem contrived. In any event, the last two parameters do occasionally come in handy.

Upvotes: 2

Related Questions