84

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?

3
  • 3
    You are asking for flatmap. See this SO answer Commented Oct 28, 2017 at 5:57
  • 6
    @RayToal Thanks. I feel like a lot of effective programming is knowing the correct terminology. Commented Oct 28, 2017 at 5:58
  • 1
    linked - stackoverflow.com/q/38528473/104380 Commented Jun 1, 2019 at 17:05

4 Answers 4

87

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]

Sign up to request clarification or add additional context in comments.

3 Comments

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.
@jfriend00 because reduce() is a functional programming method (my priority). and of course your solution works fine too.
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 )
69

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]

4 Comments

This is beautiful. very clever use of how concat works with multiple Array parameters.
TypeError: flatMap is not a function i am getting this error in node v10.18.1
It's not supported in node v10, but there are polyfills, and you can also use the [].concat() solution in the answer instead.
Other alternative would be to use .map().flat()
7

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;
}, []);

Comments

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 ]

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.