Reputation: 1211
I tried to implement an array flatten function recursively. Here is the code:
function flatten(arr) {
var flatArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] instanceof Array) {
flatArr.concat(flatten(arr[i]));
} else {
flatArr.push(arr[i]);
}
}
return flatArr;
}
console.log(flatten([1, 2, 3, 4, [5]]));
/*
result: [1, 2, 3, 4]
expected: [1, 2, 3, 4, 5]
*/
But I don't know why the result is not correct. Please help me explain it.
Upvotes: 3
Views: 2144
Reputation: 358
I am influenced by the Nina Scholz' answer (https://stackoverflow.com/a/35681232/5018572) above and made a tail call safe recursive flat array function which avoid using any iteration in it:
'use strict'
function flatten(arr, flatArr = []) {
if (arr.length === 0) {
return flatArr;
}
var [head, ...rest] = arr;
if (Array.isArray(head)) {
head.push(...rest);
return flatten(head, flatArr);
} else {
flatArr.push(head);
}
return flatten(rest, flatArr);
}
var test = [1,2,[3,4,[5,[[[6,[[[7]]]]]]]]]
console.log(flatten(test));
Upvotes: 2
Reputation: 358
I worked on another (possibly better performant) answer.
I used push
, and pop
for modifying the arrays (given and final arrays) because they're more performant array operations compare to shift
for remove the first element from given array, or spread operator for merging arrays or combining it with destruction to simulate shift
method.
I also used push
method for merging arrays (credit to this post: https://forum.freecodecamp.org/t/big-o-complexity-of-concat-vs-push-apply-inside-loops/33513).
There's a catch though: result array is reversed. push
and pop
adds/removes last item therefore I created the final array in reversed order. For this reason I called .reverse
at the end.
reverse
is executed after all flattening operations are completed, so it won't increase the complexity.
Here is the solution:
function flatten(arr, flatArr = []) {
if (arr.length === 0){
return flatArr.reverse();
}
var lastItem = arr.pop();
if(Array.isArray(lastItem)){
Array.prototype.push.apply(arr, lastItem);
return flatten(arr, flatArr);
} else {
flatArr.push(lastItem);
}
return flatten(arr, flatArr)
}
var array1 = [1,2,[3,4,[5,[[[6,[[[7, [8, 9, [10, [11,[12, [13, [[[[14,[15, [[16,[17]]]]]]]]]]]]]]]]]]]]]];
var array2 = [[[[[[[[[[[[[[[[[[[[[[[[[1],2,3]]]],4],5]]]],6],7],8],9]],10],11],12],13],14],15],16]]],17];
console.log(flatten(array1));
console.log(flatten(array2));
Upvotes: 0
Reputation: 21
This worked for me, hope it helps! :)
function flatten(array) {
let result = [];
array.forEach(el => {
if(el instanceof Array){
result.push(...flatten(el));
}else result.push(el)
});
return result
}
console.log(flatten([1, [2, 3, [4]]]));
Upvotes: 2
Reputation: 4144
Loop array until all items get flatten, It's a different solution, not exactly what asked in the question.
// loop until all items are flatten
for (var i = 0, len = data.length; i < len; i++) {
if (Array.isArray(data[i])) {
// flatten until there are no more nested
data = data.concat.apply([], data);
i--;
len = data.length;
}
}
Upvotes: 0
Reputation: 21470
The
concat()
method returns a new array comprised of the array on which it is called joined with the array(s) and/or value(s) provided as arguments.
flatArr.concat(...)
doesn't change flatArr
... you need to assign it like so:
flatArr = flatArr.concat('flatten(arr[i]));
Here is a working example with 3 levels deep array:
function flatten(arr) {
var flatArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] instanceof Array) {
flatArr = flatArr.concat(flatten(arr[i]));
} else {
flatArr.push(arr[i]);
}
}
return flatArr;
}
var arr = [1,2,3,4,[5,6,[7,8]]];
var flatten = flatten(arr);
$('#result').html(JSON.stringify(flatten));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result"></div>
You can read more about Array.concat function here
Upvotes: 6
Reputation: 386883
Maybe you like a real recursive solution:
function flatten(arr) {
if (!arr.length) {
return [];
}
var a = arr.shift();
return (Array.isArray(a) ? flatten(a) : [a]).concat(flatten(arr));
}
document.write('<pre>' + JSON.stringify(flatten([1, 2, 3, 4, [5]])) + '</pre>');
document.write('<pre>' + JSON.stringify(flatten([1, [2, 3, [4, 5]], 6, 7, [8]])) + '</pre>');
Upvotes: 3
Reputation: 67217
You have to assign the returned array
after performing the concat
,
if (arr[i] instanceof Array) {
flatArr = flatArr.concat(flatten(arr[i]));
concat
will not edit the source array. It will give you a new copy. So we have to assign it back to the source array
manually.
Upvotes: 4