Piotr Berebecki
Piotr Berebecki

Reputation: 7468

Flatten arguments into one dimensional array using the rest parameter

I've developed the following code (http://codepen.io/PiotrBerebecki/pen/KrkdPj) when trying to flatten a multidimensional array into a one-dimensional array.

For example,

flattenArray([1, [2, 3], 4, [5, [6]], 7])
// should return [1, 2, 3, 4, 5, 6, 7]


// Flatten an array
function flattenArray(input) {
  return input.reduce(function(prev, curr) {
    if (Array.isArray(curr)) {return prev.concat(flattenArray(curr));}
    else {return prev.concat(curr);}
  }, []);
}

console.log(  flattenArray([1, [2, 3], 4, [5, [6]], 7])  );
// [1, 2, 3, 4, 5, 6, 7]

The above seems to work OK.

Now, I've been asked to make another function that instead of an array will achieve the same result for a mix of numbers and arrays.

For example,

flattenMix(1, [2, 3], 4, [5, [6]], 7);
// should return [1, 2, 3, 4, 5, 6, 7]

I've slightly modified the above by adding the rest parameter so that the function can accept an arbitrary number of arguments. However I'm getting a maximum call stack error. Would you know what the problem is with the function below?

// Flatten arguments (arbitrary length) consisting of a mix of numbers and arrays
function flattenMix(...input) {
  return input.reduce(function(prev, curr) {
    if (Array.isArray(curr)) {return prev.concat(flattenMix(curr));}
    else {return prev.concat(curr);}
  }, []);
}

console.log(  flattenMix(1, [2, 3], 4, [5, [6]], 7)  ); // should return [1, 2, 3, 4, 5, 6, 7]

UPDATE 1

The answer and suggestions below have indicated that I should be using the ... spread operator in the recursive call flattenMix(...curr). In this way when the curr is an array (as tested) then the containing elements of the curr would be passed in to the flattenMix function (instead of the curr array).

Upvotes: 4

Views: 1787

Answers (4)

Anatoli Klamer
Anatoli Klamer

Reputation: 2648

There is a new method Array.flat()

var arr1 = [1, 2, [3, 4]];
arr1.flat(); 
// [1, 2, 3, 4]

var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]

var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

Upvotes: 0

Morteza Tourani
Morteza Tourani

Reputation: 3536

Your problem is that you send an array as first argument in recursion instead of array items. You can use flatten.apply(null, arr) or flatten(...arr):

// Flatten arguments (arbitrary length) consisting of a mix of numbers and arrays

function flatten(...input) {
  return input.reduce(function(prev, curr) {
    return prev.concat(
      Array.isArray(curr) ? flatten(...curr) : curr
    );
  }, []);
}

console.log(flatten(1, [2, 3], 4, [5, [6]], 7)); // should return [1, 2, 3, 4, 5, 6, 7]

Do it the fun way

If you convert an array of array to string this would flatten the array for you and the only thing you should do is to convert string numbers to Number.

function flattenArgs() {
  return Array.from(arguments).toString()
    .split(',').map(Number);
}

console.log(flattenArgs(1, [2, 3], 4, [5, [6]], 7));

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386680

Well, you could just use the spread operator.

function flattenMix(...input) {
    return input.reduce(function (prev, curr) {
        if (Array.isArray(curr)) {
            return prev.concat(flattenMix(...curr));
            //                            ^^^^^^^
        } else {
            return prev.concat(curr);
        }
    }, []);
}

console.log(flattenMix(1, [2, 3], 4, [5, [6]], 7));

Upvotes: 2

Jonathan
Jonathan

Reputation: 9151

Well, easy. Your first method can already deal with an array and since arguments is basically an array we can just add an extra line.

// Flatten an array
function flattenArray(input) {
  return input.reduce(function(prev, curr) {
    if (Array.isArray(curr)) {
      return prev.concat(flattenArray(curr));
    } else {
      return prev.concat(curr);
    }
  }, []);
}

function flattenMix() {
  return flattenArray([].slice.call(arguments));
}

console.log(flattenMix(1, [2, 3], 4, [5, [6]], 7));

Upvotes: 2

Related Questions