Categories
arrays flatten javascript merge multidimensional-array

Merge/flatten an array of arrays

1449

I have a JavaScript array like:

[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]

How would I go about merging the separate inner arrays into one like:

["$6", "$12", "$25", ...]

3

  • 32

    All of the solutions that use reduce + concat are O((N^2)/2) where as a accepted answer (just one call to concat) would be at most O(N*2) on a bad browser and O(N) on a good one. Also Denys solution is optimized for the actual question and upto 2x faster than the single concat. For the reduce folks it’s fun to feel cool writing tiny code but for example if the array had 1000 one element subarrays all the reduce+concat solutions would be doing 500500 operations where as the single concat or simple loop would do 1000 operations.

    – gman

    Jul 30, 2017 at 15:45


  • 12

    With the latest browsers that support ES2019: array.flat(Infinity) where Infinity is the maximum depth to flatten.

    Apr 6, 2020 at 2:47

  • I’m glad they put a maximum depth.. 😀

    – Magne

    Mar 14 at 14:52

2375

You can use concat to merge arrays:

var arrays = [
  ["$6"],
  ["$12"],
  ["$25"],
  ["$25"],
  ["$18"],
  ["$22"],
  ["$10"]
];
var merged = [].concat.apply([], arrays);

console.log(merged);

Using the apply method of concat will just take the second parameter as an array, so the last line is identical to this:

var merged2 = [].concat(["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]);

There is also the Array.prototype.flat() method (introduced in ES2019) which you could use to flatten the arrays, although it is only available in Node.js starting with version 11, and not at all in Internet Explorer.

const arrays = [
      ["$6"],
      ["$12"],
      ["$25"],
      ["$25"],
      ["$18"],
      ["$22"],
      ["$10"]
    ];
const merge3 = arrays.flat(1); //The depth level specifying how deep a nested array structure should be flattened. Defaults to 1.
console.log(merge3);
    

14

  • 47

    Or Array.prototype.concat.apply([], arrays).

    – danhbear

    Jan 16, 2014 at 1:03

  • 32

    Note: this answer only flattens one level deep. For a recursive flatten, see the answer by @Trindaz.

    – Phrogz

    Feb 21, 2014 at 14:01

  • 257

    Further to @Sean’s comment: ES6 syntax makes this super concise: var merged = [].concat(...arrays)

    – Sethi

    Jul 8, 2015 at 13:50

  • 2

    Building on @Sethi’s comment: Array.prototype.concat(...arrays). This version works with Typescript’s 2.3.0 --strict mode. Doesn’t work with nested arrays (it’s not recursive).

    May 16, 2017 at 8:59


  • 2

    ‘apply’ will stack overflow on large inputs for some vms, like v8. It’s really not meant for this use case.

    Mar 10, 2018 at 4:22

597

+100

Here’s a short function that uses some of the newer JavaScript array methods to flatten an n-dimensional array.

function flatten(arr) {
  return arr.reduce(function (flat, toFlatten) {
    return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
  }, []);
}

Usage:

flatten([[1, 2, 3], [4, 5]]); // [1, 2, 3, 4, 5]
flatten([[[1, [1.1]], 2, 3], [4, 5]]); // [1, 1.1, 2, 3, 4, 5]

10

  • 11

    What’s the memory usage profile for this solution? Looks like it creates a lot of intermediate arrays during the tail recursion….

    Jul 28, 2015 at 18:28

  • 3

    Why is there an empty array passed as an argument? The code breaks without it, but what does it do?

    – ayjay

    Nov 18, 2015 at 0:37

  • 9

    @ayjay, it’s the starting accumulator value for the reduce function, what mdn calls the initial value. In this case it’s the value of flat in the first call to the anonymous function passed to reduce. If it is not specified, then the first call to reduce binds the first value out of the array to flat, which would eventually result in 1 being bound to flat in both the examples. 1.concat is not a function.

    Nov 18, 2015 at 2:32


  • 32

    Or in a shorter, sexier form: const flatten = (arr) => arr.reduce((flat, next) => flat.concat(next), []);

    Aug 8, 2016 at 14:18


  • 14

    Riffing on @TsvetomirTsonev and Noah’s solutions for arbitrary nesting: const flatten = (arr) => arr.reduce((flat, next) => flat.concat(Array.isArray(next) ? flatten(next) : next), []);

    – Will

    Aug 16, 2017 at 14:24

346

There is a confusingly hidden method, which constructs a new array without mutating the original one:

var oldArray = [[1],[2,3],[4]];
var newArray = Array.prototype.concat.apply([], oldArray);
console.log(newArray); // [ 1, 2, 3, 4 ]

5

  • 1

    I’m not really convinced that this is “performant” as I seem to have hit a stack overflow with this sort of call (on an array with 200K entries which are lines in a file).

    – Steven Lu

    Feb 26, 2014 at 23:09

  • 2

    If you can use ES2015 you might also write it easier for the eye with array spreads: [].concat(...[ [1],[2,3],[4] ]).

    – Loilo

    Jan 27, 2017 at 12:37


  • 2

    did not work with array [2, [3, [4, [5, [6, [7, [8]]]]]]]

    – pareshm

    Sep 15, 2017 at 9:40


  • Very clever approach, I like it! Extremely useful if you have to flatten an array inside of an array, since using apply would presume you are passing in an array of parameters. Only bummer is if you have arrays inside your array that are more than two levels deep.

    Apr 10, 2018 at 5:14


  • I like this approach… here for n-dimensional arrays: flat = (e) => Array.isArray(e)? [].concat.apply([], e.map(flat)) : e

    – rellampec

    Jul 30, 2018 at 23:00