How does `.reduce()` actually work?

Okay, as this is a solution to the exercise, I’m going to spoiler blur it.

I get what the reduce() method (method is right, right?) is doing. But, why is the function executing without being called?

I.E. the console logs are happening without me having to call newSum();
I don’t even have to ask for newSum to be console logged. #dahell? lol!

const newNumbers = [1, 3, 5, 7];

const newSum = newNumbers.reduce((accumulator, currentValue) => {
 
  console.log('The value of accumulator: ', accumulator);
console.log('The value of currentValue: ', currentValue);
  return (accumulator + currentValue);
  
}, 10 // Second argument of reduce, sets accumulator to start at 10.);

Looks like you discovered some weirdness with the error handling of JS. This code (as shown) should not run. Are we missing some of the code?

One expects you will remove the debugging logs after this.

it is being called. are you sure you know what reduce does? be careful with assumptions so that you don’t rule out answers

Your function is just ADD, same as the + operator. Some other language might write the same thing like this instead:

(reduce + [1 3 5 7])

or

reduce (+) [1, 3, 5, 7]

or

reduce(add,  [1, 3, 5, 7])

It’s a bit easier to see what’s going on without all the boilerplate you’ve got in there.

javascript doesn’t necessarily have to be worse than the above examples:

let add = (a, b) => a + b

[1, 3, 5, 7].reduce(add)

I got this exercise but only becuase the pattern is exactly the same as all the iteratir ones that came before it. I have no idea what’s happening, why it’s happening, how it’s working.

const newNumbers = [1, 3, 5, 7];
const newSum = newNumbers.reduce((accumulator, currentValue) => {
console.log('The value of accumulator: ', accumulator);
console.log('The value of currentValue: ', currentValue);
return accumulator + currentValue;
});
console.log(newSum);

1 Like

It works because the method keeps a running total (the accumulator) as it iterates over the array, one value at a time.

total = 0
for (x of newNumbers) {
    total += x;
}
return total

Think of it like this…

Array.reduce((total, x) => total + x)

The second value is the iterator variable, the first is the running total.

We can if we wish write a separate function and use it as a callback for reduce

const plus = (s, x) => s + x;
array =  [2, 3, 5, 7, 11, 13, 17, 19]
array.reduce(plus)
// 77
1 Like

I’m just getting error codes after completing the assignment.

The value of the accumulator: 1
The value of currentValue:  3
The value of the accumulator: 4
The value of currentValue:  5
The value of the accumulator: 9
The value of currentValue:  7
/home/ccuser/workspace/javascript-iterators-reduce/main.js:12
console.log(newSum.reduce(newNumbers));
                   ^

TypeError: newSum.reduce is not a function
    at Object.<anonymous> (/home/ccuser/workspace/javascript-iterators-reduce/main.js:12:20)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.runMain (module.js:605:10)
    at run (bootstrap_node.js:427:7)
    at startup (bootstrap_node.js:151:9)
    at bootstrap_node.js:542:3

and here’s the code

const newNumbers = [1, 3, 5, 7];

const newSum = newNumbers.reduce(
  (accumulator, currentValue) => {
  
    console.log('The value of the accumulator:', accumulator);
    console.log('The value of currentValue: ', currentValue);
    
    return accumulator + currentValue;
} );

console.log(newSum.reduce(newNumbers));


1 Like

As the error message states, newSum.reduce is not a function. What that means is that a number does not have a an attribute, reduce, only list object have that method. Try,

console.log(newSum)

Do I have to use accumulator as the first variable? i.e,

Does

const newSum = newNumbers.reduce((x, y) => {
  console.log('The value of x: ', x);
  console.log('The value of y: ', y);
  return x + y;
}, 10);

work as well?

No, we can use any variable we like, as you will have seen from the above.

 Array.reduce((a, b)) => a + b)
1 Like
const newNumbers = [1, 3, 5, 7];

const newSum = newNumbers.reduce((accumulator, currentValue) => {
  console.log('The value of accumulator: ', accumulator);
  console.log('The value of currentValue: ', currentValue);
  return accumulator + currentValue;
}, 10);

console.log(newSum);

I do not understand how the arguments are being handled. Why, without an argument after the function, does accumulator take the first element of the array for value while currentValue waits for the iteration, but when adding an argument after the function then suddenly accumulator takes the value of that argument while currentValue takes the first element of the array straight away?

There must be a logic behind this, but I don’t get it. Would appreciate if someone could help me understand or direct me to a resource that explains this behavior in more details.

Imagine you are going to add up the value of a small bag of coins. First you reach into the bag with both hands, and retrieve 1 coin in each hand. We’ll make your left hand the accumulator and your right hand the currentValue. First you look at the coin in your left hand accumulator, and note its value, then you place the coin currently in your right hand currentValue into your left hand accumulator with the coin that’s already there, and add its value to the previous total. Now your left hand accumulator has 2 coins, and your right hand is empty. You reach back into the bag with only your right hand currentValue to get the next coin. Then you move the coin to you left hand accumulator adding it’s value to the previous total. Now your left hand accumulator has 3 coins, and your right hand currentValue is once again empty. You repeat this process until you’ve accumulated all of the coins into your left hand accumulator, and you know the total value of the coins that were in the bag. It’s important to note that the reduce() method does not change the original array, so at the end of my analogy, the coins would be paced back in the bag. Also, reduce() isn’t limited to addition.

Consider this very simple example, and its results:

const myArray = [2, 2, 2, 2];
console.log(myArray.reduce((a,b) => a + b));
console.log(myArray.reduce((a,b) => a - b));
console.log(myArray.reduce((a,b) => a * b));
console.log(myArray.reduce((a,b) => a / b));

Output:

8
-4
16
0.25

Hope this helps.

2 Likes

for all “visuals” of const newNumbers = [1, 3, 5, 7];

acum

late answer:

sometimes the accumulator has a shape like the array elements (like when reducing with add to get the sum, the accumulator is then a number just like the array elements. For this case the first value in the array is fine as the initial accumulator.

but the accumulator might be something else entirely, so you’d need to specify the initial value, for example: the array might contain strings, and the accumulator might be counts of how many times each letter has been seen

Maybe I just missed reading something but i still dont understand why the second argument of reduce sets accumulator to 10 when its the first parameter. Why doesnt it set currentValue?

isn’t that the same thing

This is what reduce does:

function reduce(arr, f, acc) {
  for (let e of arr) {
    acc = f(acc, e)
  }
  return acc
}