9

I have an array of objects, let's say [{x:2, y:3}, {x:5, y:4}] and i call reduce((c, n) => c.y + n.y); on it. It obviouslly returns 7.

However, if the array contains a single object, let's say [{x:2, y:4}] the same reduce call will return the object itself {x:2, y:4}.

Is this normal behaviour? Am I obliged to check if the result is an object and not an number afterwards?

5 Answers 5

20

Yes, this is the normal behaviour of reduce when you don't pass an initial value for the accumulator (which you always should). Your code doesn't work as expected on any arrays other than those with two objects.

Go for

arr.reduce((acc, el) => acc + el.y, 0)
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for the answer, just saw it in the MDN docs, I overlooked when checking. They provide a "foolproof" solution using map(), however it will affect performance, won't it ?
There's hardly any noticeable difference, use what you think is easier to understand. You don't need map, you can always integrate the mapping in your reducer function.
5

It is intended behaviour, when you don't provide an initial value (second argument to reduce). From MDN:

If the array is empty and no initialValue was provided, TypeError would be thrown. If the array has only one element (regardless of position) and no initialValue was provided, or if initialValue is provided but the array is empty, the solo value would be returned without calling callback.

It comes with the following advise:

It is usually safer to provide an initial value because there are three possible outputs without initialValue.

So write:

reduce((c, n) => c.y + n.y, { y: 0 });

Comments

4

That's because reduce function can take 1 more argument - default value and if its not specified it takes firs value of array. That's why it works for more than one.

However if you do it like this

let a = [{x:5, y:4}].reduce((c, n) => c + n.y, 0);

console.log(a)

it sums propertly.

Comments

3

Did you initialize the accumulator to { y : 0}

If you did not then it will return the original object.

let sum = data.reduce((c, n) => {
  return { "y" : c.y + n.y };
}, { y : 0 });

1 Comment

@Bergi You are right. Fixed it. Now the accumulator will always be an object with y key.
2

Note: If initialValue isn't provided, reduce will execute the callback function starting at index 1, skipping the first index. If initialValue is provided, it will start at index 0.

If the array is empty and no initialValue is provided, TypeError will be thrown. If the array has only one element (regardless of position) and no initialValue is provided, or if initialValue is provided but the array is empty, the solo value will be returned without calling callback.

It is usually safer to provide an initial value because there are three possible outputs without initialValue, as shown in the following example.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.