370

What is the most efficient way to concatenate N arrays of objects in JavaScript?

The arrays are mutable, and the result can be stored in one of the input arrays.

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Leonid
  • 22,360
  • 25
  • 67
  • 91
  • 4
    possible duplicate of [Merge/flatten an Array of Arrays in JavaScript?](http://stackoverflow.com/questions/10865025/merge-flatten-an-array-of-arrays-in-javascript) – rofrol Sep 19 '15 at 17:40

24 Answers24

436

If you're concatenating more than two arrays, concat() is the way to go for convenience and likely performance.

var a = [1, 2], b = ["x", "y"], c = [true, false];
var d = a.concat(b, c);
console.log(d); // [1, 2, "x", "y", true, false];

For concatenating just two arrays, the fact that push accepts multiple arguments consisting of elements to add to the array can be used instead to add elements from one array to the end of another without producing a new array. With slice() it can also be used instead of concat() but there appears to be no performance advantage from doing this.

var a = [1, 2], b = ["x", "y"];
a.push.apply(a, b);
console.log(a); // [1, 2, "x", "y"];

In ECMAScript 2015 and later, this can be reduced even further to

a.push(...b)

However, it seems that for large arrays (of the order of 100,000 members or more), the technique passing an array of elements to push (either using apply() or the ECMAScript 2015 spread operator) can fail. For such arrays, using a loop is a better approach. See https://stackoverflow.com/a/17368101/96100 for details.

user229044
  • 232,980
  • 40
  • 330
  • 338
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • 1
    I believe your test may have an error: the `a.concat(b)` test case seems to be needlessly making a copy of the array `a` then throwing it away. – ninjagecko Apr 22 '12 at 21:35
  • 1
    @ninjagecko: You're right. I updated it: http://jsperf.com/concatperftest/6. For the particular case of creating a new array that concatenates two existing arrays, it appears `concat()` is generally faster. For the case of concatenating an array onto an existing array in place, `push()` is the way to go. I updated my answer. – Tim Down Apr 22 '12 at 22:12
  • 22
    I can attest that extending a single array with several new arrays using the push.apply method confers a huge performance advantage (~100x) over the simple concat call. I'm dealing with very long lists of short lists of integers, in v8/node.js. – chbrown Jul 14 '12 at 03:28
  • @chbrown confirmed. I'm doing file crypto in JS (none of this `[1,2,3].concat([4,5,6])` stuff) and doing `for(var i = 0, n = arr2.length; i < n; i++) arr1.push(arr2[i]);` seems to be the fastest of any method I've seen so far for *larger datasets*. – andrew Oct 02 '13 at 18:59
  • @andrew Using For is definitely the fastest solution. However I love this: `while(b.length) a.push(b.splice(0,1)[0]);` because it is almost as fast but looks a lot slicker :D – Martin May 13 '14 at 11:25
  • I concur what @chbrown says, I had to create an array which needed concatenation around 1700 times. With a = a.concat(b) it used to take around 3 seconds including some other processing. I changed that to a.push.apply(a, b) and the time was down to milliseconds. – rd22 Jun 07 '16 at 13:00
  • 1
    An even more concise way is a.push(...b); – dan Jun 23 '17 at 21:49
  • 1
    @dinvlad: True, but only in ES6 environments. I've added a note to my answer. – Tim Down Jun 26 '17 at 09:36
  • @tim-down fair enough, i was actually using it through TypeScript which is then transpiled to ES5. The transpiled version uses `a.push.apply(a,b)` – dan Jun 27 '17 at 17:44
  • `concat` creates a new array, leaving the originals untouched, that's why it's slower than just adding new elements and it also creates more Umemory garbage to be collected. Stick with `push` unless you actually need a brand new array object. – Mani Gandham Oct 05 '17 at 00:30
  • @ManiGandham That's true but the answer does allude to that. – Tim Down Oct 06 '17 at 09:03
  • @TimDown Using `concat` is was slower than using `push`. https://codeburst.io/jsnoob-push-vs-concat-basics-and-performance-comparison-7a4b55242fa9 – Ilker Cat Jan 02 '19 at 18:49
  • fyi: https://dev.to/uilicious/javascript-array-push-is-945x-faster-than-array-concat-1oki – Paul Fabbroni Jun 24 '20 at 14:54
196
[].concat.apply([], [array1, array2, ...])

proof of efficiency: http://jsperf.com/multi-array-concat/7

Tim Supinie mentions in the comments that this may cause the interpreter to exceed the call stack size. This is perhaps dependent on the js engine, but I've also gotten "Maximum call stack size exceeded" on Chrome at least. Test case: [].concat.apply([], Array(300000).fill().map(_=>[1,2,3])). (I've also gotten the same error using the currently accepted answer, so one is anticipating such use cases or building a library for others, special testing may be necessary no matter which solution you choose.)

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
ninjagecko
  • 88,546
  • 24
  • 137
  • 145
  • 3
    @c69: it seems about as efficient as the chosen answer of repeatedly .push(#,#,...,#), on Chrome at least. http://jsperf.com/multi-array-concat The chosen answer by Tim Down may also have an error in it. This link is a performance comparison of joining multiple arrays as the question asked (not just 2); multiple possible lengths are tested. – ninjagecko Apr 22 '12 at 21:38
  • IMO this is the most effective way to "merge" n arrays, well done – Eric Uldall Mar 17 '16 at 17:16
  • 1
    This answer is particularly useful when N is not known ahead of time such as when you have an array of arrays of arbitrary length and you want them all concatenated. – jfriend00 Jul 09 '16 at 16:05
  • 5
    With ES6 and spread operators it get's even simpler: [].concat(...[array1, array2, ...]) Well, the second three dots are a bit unfortunate. The first three is the spread operator https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Spread_operator – Eydrian Feb 03 '17 at 10:53
  • Eydrian: I personally try to avoid the spread operator because it's very inefficient, but I'm not sure yet if that's because the implementation is immature, or the semantics of the es6 specification require a bit of heavier lifting (i.e. it will never get better). Haven't run any benchmarks in this particular case though. – ninjagecko Feb 05 '17 at 15:18
  • Why do you use `apply` with an empty array as the first parameter??? why not just use `var result = [].concat(arr1, arr2, ..., arrN)` ????? – Gil Epshtain Feb 08 '18 at 13:28
  • @GilEpshtain: the question asked how to concatenate N arrays. Your method would work if you wanted to type it all out (and is certainly good for N=3), but that's like someone asking how to write a for loop and telling them to just type it out 10 times. e.g. Perhaps I could have said `[].concat.apply([], arrays)` inside a `function concatArray(arrays) {...}`. – ninjagecko Feb 09 '18 at 15:15
  • @ninjagecko - when you are saying that my method will work only for 3 arrays, that's wrong! you can concat as many arrays as you want in that method. You use the same method only adding an additional step of concat-ing an empty array to the list of arrays, this step is redundant. – Gil Epshtain Feb 11 '18 at 08:59
  • @GilEpshtain: I never said that. You're misunderstanding my explanation. A multi-parameter function is not the same as a non-multi-parameter function. People are free to code it that way if they want. Once again, there is nothing wrong with your method, and it is good for small numbers of arguments, but bad for larger. It is basically the same method. – ninjagecko Feb 11 '18 at 20:12
  • Just wanted to add that this doesn't work for me. The lists are combined into a list of lists, not a concatenated list. – rjurney Jul 13 '18 at 21:07
  • @rjurney: It works for everyone else. Perhaps you are feeding in non-arrays, or something like `[[1,2,3]]` without realizing it. Otherwise you could mention your JS interpreter or browser if it truly doesn't work and test-case. – ninjagecko Jul 14 '18 at 22:43
  • @ninjagecko I got it working. It seems strange to me that Array.concat() doesn't edit the array in place. – rjurney Jul 24 '18 at 21:31
  • 1
    Just FYI, this method can fill up the call stack if N is very large. I tried a case where N is ~225K and ran into this issue. – Tim Supinie Aug 29 '18 at 05:10
  • @TimSupinie: thank you, that's very interesting! I've added that as a caveat. – ninjagecko Aug 30 '18 at 06:15
  • `[].concat(...arrs)` is slightly more efficient for smaller arrays. But `[].concat.apply([], ...arrs)` outperforms as N increases. https://jsperf.com/flatten-array-203948/ – colemars Sep 11 '19 at 09:32
58

New Answer

For array of multiple arrays and ES6, use

arr.flat();

For example:

const arr = [[1, 2, 3], [4, 5, 6], [7, 8 ,9]];
const newArr = arr.flat();
// output: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

This will work with node > 11 and modern browsers.


Old Answer

(leaving it here just in case it's needed for old node versions):

For array of multiple arrays and ES6, use

Array.prototype.concat(...arr);

For example:

const arr = [[1, 2, 3], [4, 5, 6], [7, 8 ,9]];
const newArr = Array.prototype.concat(...arr);
// output: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
David
  • 2,528
  • 1
  • 23
  • 29
  • 1
    In addition you can remove duplicate elements by using `newArr = Array.from(new Set(newArr));`. – Darius Apr 29 '18 at 00:53
  • Why in typescript does this become `any[]`? The typing is there - weird. – Simon_Weaver Aug 09 '19 at 04:32
  • This is actually pretty horribly inefficient at larger array volumes. https://jsperf.com/flatten-array-203948/ `[].concat.apply([], ...arr)` performs vastly better at large volumes. – colemars Sep 11 '19 at 09:30
50

For people using ES2015 (ES6)

You can now use the Spread Syntax to concatenate arrays:

const arr1 = [0, 1, 2],
      arr2 = [3, 4, 5];

const result1 = [...arr1, ...arr2]; // -> [0, 1, 2, 3, 4, 5]

// or...

const result2 = [...arr2, ...arr1]; // -> [3, 4, 5, 0, 1, 2]
Duncan Lukkenaer
  • 12,050
  • 13
  • 64
  • 97
38

Use Array.prototype.concat.apply to handle multiple arrays' concatenation:

var resultArray = Array.prototype.concat.apply([], arrayOfArraysToConcat);

Example:

var a1 = [1, 2, 3],
    a2 = [4, 5],
    a3 = [6, 7, 8, 9];
Array.prototype.concat.apply([], [a1, a2, a3]); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
Burnee
  • 2,453
  • 1
  • 24
  • 28
  • 2
    I like this one! Works easily with a variable number of arrays to concatenate. +1 – Joel Jul 17 '15 at 11:07
32

The concat() method is used to join two or more arrays. It does not change the existing arrays, it only returns a copy of the joined arrays.

array1 = array1.concat(array2, array3, array4, ..., arrayN);
dogbane
  • 266,786
  • 75
  • 396
  • 414
  • 1
    Sometimes I hate JavaScript for not modyfying the original array. – Vincent Hoch-Drei Oct 11 '18 at 09:11
  • @VincentHoch-Drei `concat` is specifically used for creating new arrays without mutating the original array. If you want to update `array1`, you'd have to use `array1.push(...array2, ...array3, ...array4)` – adiga Sep 08 '19 at 10:40
18

If you are in the middle of piping the result through map/filter/sort etc and you want to concat array of arrays, you can use reduce

let sorted_nums = ['1,3', '4,2']
  .map(item => item.split(','))   // [['1', '3'], ['4', '2']]
  .reduce((a, b) => a.concat(b))  // ['1', '3', '4', '2']
  .sort()                         // ['1', '2', '3', '4']
artnikpro
  • 5,487
  • 4
  • 38
  • 40
  • I like this approach best, but note that this is a hundred times slower than the `[].concat.apply` way. – Arnie97 Jan 05 '22 at 06:36
10

Now we can combine multiple arrays using ES6 Spread. Instead of using concat() to concatenate arrays, try using the spread syntax to combine multiple arrays into one flattened array. eg:

var a = [1,2];
var b = [3,4];
var c = [5,6,7];
var d = [...a, ...b, ...c];
// resulting array will be like d = [1,2,3,4,5,6,7]
chinmayan
  • 1,304
  • 14
  • 13
10

solved like this.

let arr = [[1, 2], [3, 4], [5, 6]];
 console.log([].concat(...arr));
Th1
  • 269
  • 2
  • 12
9

Shorten with ES6.

new Set([].concat(...Array));

This does concat and unique the multiple arrays;

let Array = [
  ['vue','babel','npm','gulp','mysql','less','laravel'],
  ['jquery','react','js','css','wordpress','html','bootstrap'],
  ['vue','babel','npm','gulp','mysql','less','laravel'],
  ['angular','cms','js','css','graphql','nodejs','php'],
  ['severless','headless','js','css','design','photoshop','php'],
]

const Boom = new Set([].concat(...Array));


// This is not necessary 
let dStr = '';
Boom.forEach(e=>{
  dStr += e + ' ';
})
document.write(dStr);
<div class="result"></div>
ronaldtgi
  • 687
  • 8
  • 17
7

Merge Array with Push:

const array1 = [2, 7, 4];
const array2 = [3, 5,9];
array1.push(...array2);
console.log(array1)

Using Concat and Spread operator:

const array1 = [1,2];
const array2 = [3,4];

// Method 1: Concat 
const combined1 = [].concat(array1, array2);

// Method 2: Spread
const combined2 = [...array1, ...array2];

console.log(combined1);
console.log(combined2);
Zobia Kanwal
  • 4,085
  • 4
  • 15
  • 38
4

Easily with the concat function:

var a = [1,2,3];
var b = [2,3,4];
a = a.concat(b);
>> [1,2,3,2,3,4]
Qix - MONICA WAS MISTREATED
  • 14,451
  • 16
  • 82
  • 145
Dmitri Farkov
  • 9,133
  • 1
  • 29
  • 45
  • Please keep in mind that this method is very inefficient, unfortunately https://jsperf.com/concat-small-arrays-vs-push-vs-loop/ – Dan May 15 '17 at 19:34
4

You can use jsperf.com site to compare perfomance. Here is link to concat.

Added comparison between:

var c = a.concat(b);

and:

var c = [];
for (i = 0; i < a.length; i++) {
    c.push(a[i]);
}
for (j = 0; j < b.length; j++) {
    c.push(b[j]);
}

The second is almost 10 times slower in chrome.

gor
  • 11,498
  • 5
  • 36
  • 42
  • However, you can use `push.apply()`, which seems to be faster than `concat()` in all browsers except Chrome. See my answer. – Tim Down Feb 22 '11 at 17:17
3

Here is a function by which you can concatenate multiple number of arrays

function concatNarrays(args) {
    args = Array.prototype.slice.call(arguments);
    var newArr = args.reduce( function(prev, next) {
       return prev.concat(next) ;
    });

    return newArr;
}

Example -

console.log(concatNarrays([1, 2, 3], [5, 2, 1, 4], [2,8,9]));

will output

[1,2,3,5,2,1,4,2,8,9]
Koushik Das
  • 9,678
  • 3
  • 51
  • 50
3

If you have array of arrays and want to concat the elements into a single array, try the following code (Requires ES2015):

let arrOfArr = [[1,2,3,4],[5,6,7,8]];
let newArr = [];
for (let arr of arrOfArr) {
    newArr.push(...arr);
}

console.log(newArr);
//Output: [1,2,3,4,5,6,7,8];

Or if you're into functional programming

let arrOfArr = [[1,2,3,4],[5,6,7,8]];
let newArr = arrOfArr.reduce((result,current)=>{
    result.push(...current);
    return result;
});

console.log(newArr);
//Output: [1,2,3,4,5,6,7,8];

Or even better with ES5 syntax, without the spread operator

var arrOfArr = [[1,2,3,4],[5,6,7,8]];
var newArr = arrOfArr.reduce((result,current)=>{
    return result.concat(current);
});
console.log(newArr);
//Output: [1,2,3,4,5,6,7,8];

This way is handy if you do not know the no. of arrays at the code time.

0xC0DED00D
  • 19,522
  • 20
  • 117
  • 184
1

where 'n' is some number of arrays, maybe an array of arrays . . .

var answer = _.reduce(n, function(a, b){ return a.concat(b)})

rashadb
  • 2,515
  • 4
  • 32
  • 57
1

If there are only two arrays to concat, and you actually need to append one of arrays rather than create a new one, push or loop is the way to go.

Benchmark: https://jsperf.com/concat-small-arrays-vs-push-vs-loop/

Dan
  • 55,715
  • 40
  • 116
  • 154
1

try this:

i=new Array("aaaa", "bbbb");
j=new Array("cccc", "dddd");

i=i.concat(j);
JAiro
  • 5,914
  • 2
  • 22
  • 21
1

if the N arrays are gotten from the database and not hardcoded, the i'll do it like this using ES6

let get_fruits = [...get_fruits , ...DBContent.fruit];
1

The fastest by a factor of 10 is to iterate over the arrays as if they are one, without actually joining them (if you can help it).

I was surprised that concat is slightly faster than push, unless the test is somehow unfair.

const arr1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
const arr2 = ['j', 'k', 'l', 'i', 'm', 'n', 'o', 'p', 'q', 'r', 's'];
const arr3 = ['t', 'u', 'v', 'w'];
const arr4 = ['x', 'y', 'z'];

let start;

// Not joining but iterating over all arrays - fastest
// at about 0.06ms
start = performance.now()

const joined = [arr1, arr2, arr3, arr4];

for (let j = 0; j < 1000; j++) {
  let i = 0;
  while (joined.length) {
    // console.log(joined[0][i]);
    if (i < joined[0].length - 1) i++;
    else {
      joined.shift()
      i = 0;
    }
  }
}

console.log(performance.now() - start);

// Concating (0.51ms).
start = performance.now()

for (let j = 0; j < 1000; j++) {
  const a = [].concat(arr1, arr2, arr3, arr4);
}

console.log(performance.now() - start);

// Pushing on to an array (mutating). Slowest (0.77ms)
start = performance.now()

const joined2 = [arr1, arr2, arr3, arr4];

for (let j = 0; j < 1000; j++) {
  const arr = [];
  for (let i = 0; i < joined2.length; i++) {
    Array.prototype.push.apply(arr, joined2[i])
  }
}

console.log(performance.now() - start);

You can make the iteration without joining cleaner if you abstract it and it's still twice as fast:

const arr1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
const arr2 = ['j', 'k', 'l', 'i', 'm', 'n', 'o', 'p', 'q', 'r', 's'];
const arr3 = ['t', 'u', 'v', 'w'];
const arr4 = ['x', 'y', 'z'];

function iterateArrays(arrays, onEach) {
  let i = 0;
  while (joined.length) {
    onEach(joined[0][i]);
    if (i < joined[0].length - 1) i++;
    else {
      joined.shift();
      i = 0;
    }
  }
}

// About 0.23ms.
let start = performance.now()

const joined = [arr1, arr2, arr3, arr4];

for (let j = 0; j < 1000; j++) {
  iterateArrays(joined, item => {
    //console.log(item);
  });
}

console.log(performance.now() - start);
Dominic
  • 62,658
  • 20
  • 139
  • 163
1

You can use this -

let array2d = [[1, 2, 3], [5, 4], [7, 8]];

let array1d = array2d.reduce((merged, block) => {
                          merged.push(...block); 
                          return merged; 
                     }, []);

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

OR this which I liked from one of the answers above -

let array2d = [[1, 2, 3], [5, 4], [7, 8]];
console.log([].concat(...array2d)); // [1, 2, 3, 5, 4, 7, 8]

OR this which I discovered -

let array2d = [[1, 2, 3], [5, 4], [7, 8]];
console.log(array2d.join().split(',').map(Number); // [1, 2, 3, 5, 4, 7, 8]
finiteEffort
  • 117
  • 1
  • 4
0

It appears that the correct answer varies in different JS engines. Here are the results I got from the test suite linked in ninjagecko's answer:

  • [].concat.apply is fastest in Chrome 83 on Windows and Android, followed by reduce (~56% slower);
  • looped concat is fastest in Safari 13 on Mac, followed by reduce (~13% slower);
  • reduce is fastest in Safari 12 on iOS, followed by looped concat (~40% slower);
  • elementwise push is fastest in Firefox 70 on Windows, followed by [].concat.apply (~30% slower).
BenW
  • 489
  • 3
  • 8
0

You can check this blog, here the performance for both push() and concat() has been compared. Also custom functions are made which performs better in specific scenario.

https://dev.to/uilicious/javascript-array-push-is-945x-faster-than-array-concat-1oki

Satyam Rai
  • 361
  • 1
  • 3
  • 14
0

Remember that concat array can also have duplicates, sorting of items.

Step 1

Concat the arrays

let insights = emptyInsights.concat(defaultInsights, softInsights);

Step 2

Remove the duplicates

insights = [...new Set(insights)];

Step 3

Sort the array

insights = insights.sort((a: Insight, b: Insight) =>
          a.publishedDate > b.publishedDate ? -1 : 1
        );
Surya R Praveen
  • 3,393
  • 1
  • 24
  • 25