Reputation: 338
So I am trying to get my head around recursion and recently came across a problem which was easiest solved using recursion anyway. I am trying to flatten an array of varying depth arrays and the function I cam up with to do this was:
mixedArray = [1, 2, [3, 4], [[5, 6], 7], 8, 9];
function flattenArray(array) {
return array.map(val => {
if (typeof val !== "number") {
return flattenArray(val);
} else {
return val;
}
});
}
console.log(flattenArray(mixedArray));
Now, I am expecting this to output [1,2,3,4,5,6,7,8,9] but it just returns mixedArray as is. My thinking was that it takes the array and (assuming that the array is not just a single number) maps through the entries. If an entry is a single number then it should return that number if it is not, then it should call the original function on this entry, and so on and so forth. Hopefully this is something fairly basic like a syntax error (which would be fairly typical!!)
Please note; I would like to know WHY my function is not working as well as looking at a solution.
Thanks (in advance)
Upvotes: 0
Views: 57
Reputation: 350252
You cannot do that with a plain map
method, as that will just return the same number of elements as in the array the map
is applied on (i.e., the top level).
Instead use reduce
, and then make sure to extend what you already have with whatever must be added to it:
mixedArray = [1, 2, [3, 4], [[5, 6], 7], 8, 9];
function flattenArray(array) {
return array.reduce( (flat, val) => {
if (typeof val !== "number") {
return [...flat, ...flattenArray(val)];
} else {
return [...flat, val];
}
}, []);
}
console.log(flattenArray(mixedArray));
You can use a ternary operator instead of if ... else
to condense the code a bit:
mixedArray = [1, 2, [3, 4], [[5, 6], 7], 8, 9];
const flattenArray = array =>
array.reduce( (flat, val) =>
[...flat, ...(Array.isArray(val) ? flattenArray(val) : [val])]
, []);
console.log(flattenArray(mixedArray));
... and of course, we should mention the ESNext proposal Array#flat, which just does all that in one method call.
mixedArray = [1, 2, [3, 4], [[5, 6], 7], 8, 9];
console.log(mixedArray.flat(Infinity));
Upvotes: 5
Reputation: 17190
I will modify it into something like this. Because you actually are mapping all elements to the same elements:
mixedArray = [1, 2, [3, 4], [[5, 6], 7], 8, 9];
function flattenArray(array, out=[])
{
array.forEach(val =>
{
if (typeof val !== "number")
out = out.concat(flattenArray(val));
else
out.push(val);
});
return out;
}
console.log(flattenArray(mixedArray));
Upvotes: 1
Reputation: 93348
The issue is that mapping an array to an array doesn't change it, it's still an array in the resulting array:
function flattenArray(array) {
return array.reduce((result, x) => result.concat(
Array.isArray(x) ? flattenArray(x) : x), [])
}
That should do the same but uses reduce rather than map.
Upvotes: 2