Return multiple values from ES6 map() function
Asked Answered
I

4

76

Say I have something like this:

let values = [1,2,3,4]; 

let newValues = values.map((v) => {
  return v *v ; 
}); 

console.log(newValues); //[1,4,9,16]

Pretty straight forward.

Now what if I want to return multiple values for each of my objects?

eg.

let values = [1,2,3,4]; 

let newValues = values.map((v) => {
  return [v *v, v*v*v, v+1] ; 
}); 

console.log(newValues); //This is what I want to get 
                        //[1, 1, 2, 4, 8, 3, 9, 27, 4, 16, 64, 5]

I can use a reduce function

let values = [1,2,3,4]; 

let newValues = values.map((v) => {
  return [v *v, v*v*v,v+1] ;
}).reduce((a, c) => {

  return a.concat(c); 
}); 

console.log(newValues); 

But is that the best way to do this?

Ischium answered 28/10, 2017 at 5:54 Comment(3)
You are asking for flatmap. See this SO answerForwarding
@RayToal Thanks. I feel like a lot of effective programming is knowing the correct terminology.Ischium
linked - https://mcmap.net/q/266894/-array-map-1-element-to-multiple-element/104380Scandian
F
84

With using only one reduce() you can do this. you don't need map(). better approach is this:

const values = [1,2,3,4];
const newValues= values.reduce((acc, cur) => {
  return acc.concat([cur*cur , cur*cur*cur, cur+1]);
    // or acc.push([cur*cur , cur*cur*cur, cur+1]); return acc;
}, []);

console.log('newValues =', newValues)

EDIT: The better approach is just using a flatMap (as @ori-drori mentioned):

const values = [1,2,3,4]; 

const newValues = values.flatMap((v) => [v *v, v*v*v, v+1]); 

console.log(JSON.stringify(newValues)); //[1, 1, 2, 4, 8, 3, 9, 27, 4, 16, 64, 5]
Farinaceous answered 28/10, 2017 at 6:6 Comment(3)
Why not just use .push() rather than create a new array every time through the loop? You can pass multiple values to .push(). In fact, you don't really need to use .reduce() either. for/of or .forEach() will work just fine where you just .push() values in to a previously declared array.Kimberelykimberlee
@Kimberelykimberlee because reduce() is a functional programming method (my priority). and of course your solution works fine too.Farinaceous
Dislike because (1) this is very slow - On^2 - and (2) there is a built in fn flatMap no need for bad practices ( implementing another function besides the official one )Erelong
L
64

If you need to map an array, and flatten the results you can use Array.flatMap():

const values = [1,2,3,4]; 

const newValues = values.flatMap((v) => [v *v, v*v*v, v+1]); 

console.log(JSON.stringify(newValues)); //[1, 1, 2, 4, 8, 3, 9, 27, 4, 16, 64, 5]

If Array.flatMap() is not available flatten the results of the map by using Array#concat and the spread syntax:

const values = [1,2,3,4]; 

const newValues = [].concat(...values.map((v) => [v *v, v*v*v, v+1])); 

console.log(JSON.stringify(newValues)); //[1, 1, 2, 4, 8, 3, 9, 27, 4, 16, 64, 5]
Ludwigg answered 28/10, 2017 at 8:45 Comment(4)
This is beautiful. very clever use of how concat works with multiple Array parameters.Scandian
TypeError: flatMap is not a function i am getting this error in node v10.18.1Woodsia
It's not supported in node v10, but there are polyfills, and you can also use the [].concat() solution in the answer instead.Ludwigg
Other alternative would be to use .map().flat()Rostrum
K
6

By definition, .map() returns an array of the same length as the input array so it's just not a good choice when you want to create a different length result.

From an efficiency point of view, it's probably best to use for/of and avoid creating lots of intermediate arrays:

let values = [1,2,3,4];

let result = [];
for (let val of values) {
    result.push(val*val , val*val*val, val+1);
}

If you wanted to use array methods efficiently, you could use .reduce() with .push() to avoid creating a new array on every iteration:

let values = [1,2,3,4]; 

let result = values.reduce((array, val) => {
    array.push(val*val , val*val*val, val+1);
    return array;
}, []);
Kimberelykimberlee answered 28/10, 2017 at 6:55 Comment(0)
S
0

Better use flatMap from lodash

 const output = _.flatMap([1,2,3,4], (v, index, arr) => [v *v, v*v*v, v+1])

output: [ 1, 1, 2, 4, 8, 3, 9, 27, 4, 16, 64, 5 ]

Sazerac answered 10/4, 2018 at 13:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.