JohnnyBizzle
JohnnyBizzle

Reputation: 979

Flatten at array using Javascript

The problem is to try and remove nested arrays:

steamrollArray([1, [2], [3, [[4]]]]); // should return [1, 2, 3, 4]

I have tried this but the recursion is failing when a nested array appears.

function checkElement(el) {
    if (Array.isArray(el)) {
        if (el.length === 1) {
            return checkElement(el[0]); 
        } else {
            for (var i=0; i < el.length; i++){
                checkElement(el[i]); 
            }  
        }

    } else {
        return (el);    
    }   
}

function steamrollArray(arr) {
  var finalArr = [];
    for (var i=0; i < arr.length; i++){
        finalArr.push(checkElement(arr[i])); 
    }  


  return (finalArr);

}

Upvotes: 1

Views: 1289

Answers (9)

Pratik Barasia
Pratik Barasia

Reputation: 561

A simpler solution without using any recursion is by using splice method of Arrays. It works for any level of nesting.

function flattenArray(arr){

  for(var i=0;i<arr.length;i++){

    if(arr[i] instanceof Array){

      Array.prototype.splice.apply(arr,[i,1].concat(arr[i]))
       i--;
    }

  }

  return arr;
}

Upvotes: 0

Morteza Tourani
Morteza Tourani

Reputation: 3536

I think this would be the funniest way to do this and also it's one line no more. Also it leaves extraction to native code which is much faster than Scripting.

var nestedArray = [1, [2], [3, [[4]]]];
var flatten = nestedArray.toString().split(',').map(Number);

console.log(flatten);

Upvotes: 2

le_m
le_m

Reputation: 20228

Using a generator function allows you to efficiently iterate through nested array elements without allocating unnecessary memory. If you really need the flattened array itself, use [...iterable] or Array.from(iterable):

function* deepIterate(array) {
  for (a of array) Array.isArray(a) ? yield* deepIterate(a) : yield a;
}

// Iterate through flattened array:
for (a of deepIterate([1,[2,[3]]])) console.log(a);

// Flatten array:
var flat = Array.from(deepIterate([1,[2,[3]]]));
console.log(flat);

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386570

A proposal for the first part:

You could change the return value to array and use concat instead of push.

function checkElement(el) {
    // collect the values of the checked array
    var temp = [];
    if (Array.isArray(el)) {
        if (el.length === 1) {
            return checkElement(el[0]);
        } else {
            for (var i = 0; i < el.length; i++) {
                // collect the values
                temp = temp.concat(checkElement(el[i]));
            }
            // return flat values
            return temp;
        }
    } else {
        return el;
    }
}

// this can be shorten to
function steamrollArray(arr) {
    return checkElement(arr);
}

console.log(steamrollArray([1, [2], [3, [[4]]]]));

Part two, a bit shorter:

function steamrollArray(arr) {
    return arr.reduce(function flat(r, a) {
        return Array.isArray(a) && a.reduce(flat, r) || r.concat(a);
    }, []);
}

console.log(steamrollArray([1, [2], [3, [[4]]]]));

Upvotes: 3

Nitesh Shaw
Nitesh Shaw

Reputation: 216

Try This if it work for you

function steamrollArray(unflatenArr) {
    var flatenArr = [];
    if (Array.isArray(unflatenArr)) {
        for (var i = 0; i < unflatenArr.length; i++)
            arrFlat(unflatenArr[i], flatenArr);
    }
    return flatenArr;
}
function arrFlat(arr, refArr) {
    if (Array.isArray(arr)) {
        for (var i = 0; i < arr.length; i++) {
            arrFlat(arr[i], refArr);
        }
    }
    else {
        refArr.push(arr);
    }
}

Upvotes: 0

pishpish
pishpish

Reputation: 2614

You could use reduce:

function flatten( array ){
  return array.reduce( function (a, b){
    return a.concat( Array.isArray(b) ? flatten(b) : b );
  }, [] );
}

Upvotes: 2

Ismail RBOUH
Ismail RBOUH

Reputation: 10450

You can use recursion like this:

function flatten(array) {
    var flat = []; //The result array
    //An IIFE that will perform the recursion,
    //is equivalent to: function rec(param) {.....}; rec(param);
    (function rec(a) {
        //For each element in the array:
        //If the element is an array then call the 'rec' function.
        //Else, push it to the result array.
        //I used the conditional (ternary) operator (condition ? expr1 : expr2 )
        for(var i in a) Array.isArray(a[i]) ? rec(a[i]) : flat.push(a[i]);
    })(array);//Initiate the recursion with the main array 
    return flat;//Return the final result
};

var a = [1, [2], [3, [[4]]]];


function flatten(array) {
    var flat = [];      
    (function rec(a) {
        for(var i in a) Array.isArray(a[i]) ? rec(a[i]) : flat.push(a[i]);
    })(array);        
    return flat;
};

console.log(flatten(a));

Upvotes: 1

Nitesh Shaw
Nitesh Shaw

Reputation: 216

Try this:

function steamrollArray(unflatenArr){
    return eval("["+(JSON.stringify(unflatenArr).replace(/\[/g,'').replace(/\]/g,''))+"]")
}

steamrollArray([1, [2], [3, [[4]]]]);

Upvotes: -1

Denys S&#233;guret
Denys S&#233;guret

Reputation: 382130

You can't just return the values, or it wouldn't work when you have arrays of length > 1.

Here's a solution:

function steamrollArray(arr, flattened) {
    if (!flattened) flattened = [];
    for (var i=0; i < arr.length; i++){
         if (Array.isArray(arr[i])) {
             steamrollArray(arr[i], flattened);
         } else {
             flattened.push(arr[i]);
         }
    }  
    return flattened;
}

console.log(steamrollArray([1, [2], [3, [[4]]]])); // should return [1, 2, 3, 4]

Upvotes: 0

Related Questions