73

Why does a return of the push method cause

Uncaught TypeError: acc.push is not a function

But a return concat results in the correct solution?

[1, 2, 3, 4].reduce(function name(acc, curr) {
  if (even(curr)) {
    return acc.push(curr);
  }
  return acc;
}, []);


function even(number) {
  if (number % 2 === 0) {
    return true;
  }
  return false;
}

[1, 2, 3, 4].reduce(function name(acc, curr) {
  if (even(curr)) {
    return acc.concat(curr);
  }
  return acc;
}, []);


function even(number) {
  if (number % 2 === 0) {
    return true;
  }
  return false;
}
Nguyễn Văn Phong
  • 13,506
  • 17
  • 39
  • 56

4 Answers4

103

The push() adds elements to the end of an array and returns the new length of the array. Thus your return here is invalid.

The concat() method is used to merge arrays. Concat does not change the existing arrays, but instead returns a new array.

Better to filter, if you want a NEW array like so:

var arr = [1, 2, 3, 4];
var filtered = arr.filter(function(element, index, array) {
  return (index % 2 === 0);
});

Note that assumes the array arr is complete with no gaps - all even indexed values. If you need each individual, use the element instead of index

var arr = [1, 2, 3, 4];
var filtered = arr.filter(function(element, index, array) {
  return (element% 2 === 0);
});
Mark Schultheiss
  • 32,614
  • 12
  • 69
  • 100
10

According to the MDN document say that:

  • push() method: adds one or more elements to the end of an array and returns the new length of the array.
const count = ['pigs', 'goats'].push('cows');
console.log(count); // expected output: 3
  • concat() method is used to merge two or more arrays. This method does not change the existing arrays but instead returns a new array
console.log(['a'].concat(['b']));// expected output: Array ["a", "b"]

And combined with the final Array#reduce's parameter is the array initialize []), which means that you want to return an array result.

==> So that's the reason why in case that you use concat working well.


Refactor code

  1. If you still want to use Array#reduce and Array#push

const even = (number) => number%2 === 0;
const result = [1, 2, 3, 4].reduce(function name(acc, curr) {
  if(even(curr)) acc.push(curr); // Just add one more item instead of return
  return acc;
}, []);

console.log(result);
  1. The simpler way is to use Array#filter

const even = (number) => number%2 === 0;
console.log([1, 2, 3, 4].filter(even));
Nguyễn Văn Phong
  • 13,506
  • 17
  • 39
  • 56
7

acc should not be an array. Look at the documentation. It can be one, but..

It makes no sense at all to reduce an array to an array. What you want is filter. I mean, reduce using an array as the accumulator and concating each element to it technically does work, but it is just not the right approach.

var res = [1, 2, 3, 4].filter(even);
console.log(res);


function even(number) {
  return (number % 2 === 0);
}
Karl Reid
  • 2,147
  • 1
  • 10
  • 16
  • 1
    I agree. It was an exam question, I was asked to reimplement filter by using reduce. I had been a little fuzzy on the specs and was only looking for clarification. – The cows are in the Meadow Aug 25 '17 at 08:43
  • Say you had an array of numbers that you want to transform to an an array of the running sum of those numbers eg. [1,2,7,4] -> [1,3,10,14]. In this case would reduce with acc being an array be appropriate? – apricity Jul 05 '18 at 19:05
  • Its a fine approach actually especially if you chain together operations to avoid running multiple loops, look up "transducers and loop fusion" – Babakness Sep 22 '18 at 00:12
  • If you are transforming an array to another array with different values that is shorter (or longer) than the original, then reduce() is perfect. – Jeff Lowery Mar 07 '19 at 23:54
  • I think that arr.filter is a better approach in this case. Although according to documentation you can use arr.reduce this wayI think that it is commonly accepted that .reduce is used to create one variable from all values in an array. – Maciej Dejewski Jan 17 '20 at 00:39
6

https://dev.to/uilicious/javascript-array-push-is-945x-faster-than-array-concat-1oki Concat is 945x slower than push only because it has to create a new array.

shiv garg
  • 761
  • 1
  • 8
  • 26