43

I have [3, 16, 120]. when I do [3, 16, 120].map(mapper), I want to achieve, for example [4,5, 17,18, 121,122] i.e. each element map to n+1 and n+2. This is of course an example - what I want is to simply push multiple values from mapper function

Do I have to use Array.each and push to an array, or is it possible to do it with Array.map (or other built-in api)

Boyang
  • 2,520
  • 5
  • 31
  • 49
  • You could probably use `Array.reduce`, though I'm not sure it would be any better than using `Array.forEach`. – jcaron Jul 22 '16 at 14:11

10 Answers10

42

You can use reduce() and add to array e+1, e+2 of each element.

var ar = [3, 16, 120];

var result = ar.reduce(function(r, e) {
  r.push(e+1, e+2);
  return r;
}, []);

console.log(result)

This is ES6 version with arrow function

var ar = [3, 16, 120];

var result = ar.reduce((r, e) => r.push(e+1, e+2) && r, []);
console.log(result)

PS: Array.push seems to be faster and has no Maximum call stack.. error, see below:

a = Array(1000000).fill(1); st = Date.now(); Array.prototype.concat.apply([], a.map(function (n) { return [n+1, n+2]; })); console.log(`${Date.now() - st}ms `);
> RangeError: Maximum call stack size exceeded

a = Array(1000000).fill(1); st = Date.now(); a.reduce((r, e) => r.push(e+1, e+2) && r, []); console.log(`${Date.now() - st}ms `);
> 180ms

So .push is preferable comparing to accepted solution.

Kostanos
  • 9,615
  • 4
  • 51
  • 65
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
  • 2
    You're modifying `r` in the callback, which means this is just an unnecessarily complicated `for` loop. – melpomene Jul 22 '16 at 14:13
  • I just added performance test to answer, and it seems to be `.push` is preferable comparing to `.concat` in this case. Also concat will throw `Maximum call stack` exception for big arrays – Kostanos Dec 06 '17 at 03:54
  • check @jabacchetta's answer below https://stackoverflow.com/a/58479956/782114 – iloahz Jun 28 '23 at 12:25
26

2019 Update

Use Array.prototype.flatMap(), introduced in ES10.

const oddNumbers = [1, 3, 5, 7, 9];
const allNumbers = oddNumbers.flatMap((number) => [number, number + 1]);
console.log(allNumbers); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
jabacchetta
  • 45,013
  • 9
  • 63
  • 75
20

I come up with one myself, using spread operator.

[].concat(...[3, 16, 120].map(x => [x+1, x+2]))

Boyang
  • 2,520
  • 5
  • 31
  • 49
11

Not particularly nice, but it is a possible solution:

var arr = [3, 16, 120];

console.log([].concat.apply([], arr.map(function (n) { return [n+1, n+2]; })));
melpomene
  • 84,125
  • 8
  • 85
  • 148
  • you should consider using `Array.prototype.concat` instead of `[].concat`. Its shorter but you are allocating a new array everytime this runs – eltonkamami Jul 22 '16 at 14:34
  • 2
    @eltonkamami I'm already allocating n+3 arrays anyway. n+4 isn't going to make things much worse. – melpomene Jul 22 '16 at 14:36
4

you could produce an array for each items, then concat all these arrays :

[3, 16, 120].map(x => [x+1, x+2] ).reduce( (acc,val) => acc.concat(val), []);
Olivier Boissé
  • 15,834
  • 6
  • 38
  • 56
4

You could use Array#reduce in combination with Array#concat.

console.log([3, 16, 120].reduce(function (r, a) {
    return r.concat(a + 1, a + 2);
}, []));

ES6

console.log([3, 16, 120].reduce((r, a) => r.concat(a + 1, a + 2), []));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
3

Immutable solution, with the spread operator:

[3, 16, 120].reduce((a, v) => [...a, v+1, v+2], [])
Freewalker
  • 6,329
  • 4
  • 51
  • 70
2

using Array#concat and Array#map

Array.prototype.concat.apply([], [3, 16, 120].map(x => [x+1, x+2] ));
eltonkamami
  • 5,134
  • 1
  • 22
  • 30
2

Just for fun, an ES6 solution with a generator:

var arr = [3, 16, 120];

var [...result] = (function*() { for( i of arr){ yield ++i; yield ++i; }})();

console.log(result);
Me.Name
  • 12,259
  • 3
  • 31
  • 48
  • I never know this can work... 1. generator can be expanded with spread operator (well, it's iterable) 2. spread operator is slower than assignment Good one! – Boyang Jul 22 '16 at 15:47
2

Using Array.prototype.flat():

const doubled = [3, 16, 120].map(item => [item + 1, item + 2]).flat();

console.log(doubled)

Fair warning – not a standard method to this date (posted 12/2018).

HynekS
  • 2,738
  • 1
  • 19
  • 34