How to extend an existing JavaScript array with another array, without creating a new array?

DzinX Source

Note: This is not a duplicate of How to append something to an array? -- the goal here is to add the whole contents of one array to the other, and to do it "in place", i.e. without copying all elements of the extended array.

There doesn't seem to be a way to extend an existing JavaScript array with another array, i.e. to emulate Python's extend method.

What I want to achieve is the following:

>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
>>> a
[1, 2, 3, 4, 5]

I know there's a a.concat(b) method, but it creates a new array instead of simply extending the first one. I'd like an algorithm that works efficiently when a is significantly larger than b (i.e. one that does not copy a).

javascriptarraysconcatenation

Answers

answered 9 years ago DzinX #1

The .push method can take multiple arguments, so by using .apply to pass all the elements of the second array as arguments to .push, you can get the result you want:

>>> a.push.apply(a, b)

or perhaps, if you think it's clearer:

>>> Array.prototype.push.apply(a,b)

If your browser supports ES6, you can use the spread operator, which is more compact and elegant:

>>> a.push(...b)

Please note that all these solutions will fail with a stack overflow error if array b is too long (trouble starts at about 100,000 elements, depending on the browser). If you cannot guarantee that b is short enough, you should use a standard loop-based technique described in the other answer.

answered 9 years ago Rafał Dowgird #2

It is possible to do it using splice():

b.unshift(b.length)
b.unshift(a.length)
Array.prototype.splice.apply(a,b) 
b.shift() // restore b
b.shift() // 

But despite being uglier it is not faster than push.apply, at least not in Firefox 3.0. Posted for completeness sake.

answered 6 years ago Pizzaiola Gorgonzola #3

I like the a.push.apply(a, b) method described above, and if you want you can always create a library function like this:

Array.prototype.append = function(array)
{
    this.push.apply(this, array)
}

and use it like this

a = [1,2]
b = [3,4]

a.append(b)

answered 5 years ago jcdude #4

You should use a loop-based technique. Other answers on this page that are based on using .apply can fail for large arrays.

A fairly terse loop-based implementation is:

Array.prototype.extend = function (other_array) {
    /* you should include a test to check whether other_array really is an array */
    other_array.forEach(function(v) {this.push(v)}, this);    
}

You can then do the following:

var a = [1,2,3];
var b = [5,4,3];
a.extend(b);

DzinX's answer (using push.apply) and other .apply based methods fail when the array that we are appending is large (tests show that for me large is > 150000 entries approx in Chrome, and > 500000 entries in Firefox). You can see this error occurring in this jsperf.

An error occurs because the call stack size is exceeded when 'Function.prototype.apply' is called with a large array as the second argument. (The MDN has a note on the dangers of exceeding call stack size using Function.prototype.apply - see the section titled "apply and built-in functions")

For a speed comparison with other answers on this page check out this jsperf (thanks to EaterOfCode). The loop-based implementation is similar in speed to using Array.push.apply, but tends to be a little slower than Array.slice.apply.

Interestingly, if the array you are appending is sparse, the forEach based method above can take advantage of the sparsity and outperform the .apply based methods, check out this jsperf if you want to test this for yourself.

By the way, do not be tempted (as I was!) to further shorten the forEach implementation to:

Array.prototype.extend = function (array) {
    array.forEach(this.push, this);    
}

because this produces garbage results! Why? Because Array.prototype.forEach provides 3 arguments to the function it calls - these are: (element_value, element_index, source_array). All of these will be pushed onto your first array for every iteration of forEach if you use "forEach(this.push, this)"!

answered 5 years ago zCoder #5

Combining the answers...

Array.prototype.extend = function(array) {
    if (array.length < 150000) {
        this.push.apply(this, array)
    } else {
        for (var i = 0, len = array.length; i < len; ++i) {
            this.push(array[i]);
        };
    }  
}

answered 5 years ago Jules Colle #6

If you want to use jQuery, there is $.merge()

Example:

a = [1, 2];
b = [3, 4, 5];
$.merge(a,b);

Result: a = [1, 2, 3, 4, 5]

answered 3 years ago odinho - Velmont #7

For those that simply searched for "javascript array extend" and got here, you can very well use Array.concat.

var a = [1, 2, 3];
a = a.concat([5, 4, 3]);

Concat will return a copy the new array, as thread starter didn't want. But you might not care (certainly for most kind of uses this will be fine).


There's also some nice ES6 sugar for this in the form of the spread operator:

const a = [1, 2, 3];
const b = [...a, 5, 4, 3];

(also copies)

answered 3 years ago Mr. Polywhirl #8

You can create a polyfill for extend as I have below. It will add to the array; in-place and return itself, so that you can chain other methods.

if (Array.prototype.extend === undefined) {
  Array.prototype.extend = function(other) {
    this.push.apply(this, arguments.length > 1 ? arguments : other);
    return this;
  };
}

function print() {
  document.body.innerHTML += [].map.call(arguments, function(item) {
    return typeof item === 'object' ? JSON.stringify(item) : item;
  }).join(' ') + '\n';
}
document.body.innerHTML = '';

var a = [1, 2, 3];
var b = [4, 5, 6];

print('Concat');
print('(1)', a.concat(b));
print('(2)', a.concat(b));
print('(3)', a.concat(4, 5, 6));

print('\nExtend');
print('(1)', a.extend(b));
print('(2)', a.extend(b));
print('(3)', a.extend(4, 5, 6));
body {
  font-family: monospace;
  white-space: pre;
}

answered 3 years ago maytham-ɯɐɥʇʎɐɯ #9

I can see very nice answers, and all depends on your array size, your requirement and goal. It can be done different ways.

I suggest using JavaScript For Loop:

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

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

console.log(a) output will be

Array [ 1, 2, 3, 4, 5 ]

Then you can make your own function:

function extendArray(a, b){
    for (i = 0; i < b.length; i++) {
        a.push(b[i]);
    }
    return a;
}

console.log(extendArray(a, b)); output will be

Array [ 1, 2, 3, 4, 5 ]

answered 3 years ago Timothy Trousdale #10

The answer is super simple.

>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
(the following code will combine the 2 arrays)

a = a.concat(b);

>>> a
[1, 2, 3, 4, 5]

Concat acts very similarly to javascript string concatenation. It will return a combination of the parameter you put into the concat function on the end of the array you call the function on. The crux is that you have to asign the returned value to a variable or it gets lost. so for example

a.concat(b);  <---This does absolutely nothing since it is just returning the combined arrays but it doesn't do anything with it

answered 3 years ago odinho - Velmont #11

I feel the most elegant these days is:

arr1.push(...arr2);

The MDN article on the spread operator mentions this nice sugary way in ES2015 (ES6):

A better push

Example: push is often used to push an array to the end of an existing array. In ES5 this is often done as:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
// Append all items from arr2 onto arr1
Array.prototype.push.apply(arr1, arr2);

In ES6 with spread this becomes:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1.push(...arr2);

Do note that arr2 can't be huge (keep it under about 100 000 items), because the call stack overflows, as per jcdude's answer.

answered 2 years ago user3126309 #12

Another solution to merge more than two arrays

var a = [1, 2],
    b = [3, 4, 5],
    c = [6, 7];

// Merge the contents of multiple arrays together into the first array
var mergeArrays = function() {
 var i, len = arguments.length;
 if (len > 1) {
  for (i = 1; i < len; i++) {
    arguments[0].push.apply(arguments[0], arguments[i]);
  }
 }
};

Then call and print as:

mergeArrays(a, b, c);
console.log(a)

Output will be: Array [1, 2, 3, 4, 5, 6, 7]

answered 1 year ago Alireza #13

First a few words about apply() in JavaScript to help understand why we use it:

The apply() method calls a function with a given this value, and arguments provided as an array.

Push expects a list of items to add to the array. The apply() method, however, takes the expected arguments for the function call as an array. This allows us to easily push the elements of one array into another array with the builtin push() method.

Imagine you have these arrays:

var a = [1, 2, 3, 4];
var b = [5, 6, 7];

and simply do this:

Array.prototype.push.apply(a, b);

The result will be:

a = [1, 2, 3, 4, 5, 6, 7];

The same thing can be done in ES6 using the spread operator ("...") like this:

a.push(...b); //a = [1, 2, 3, 4, 5, 6, 7]; 

Shorter and better but not fully supported in all browsers at the moment.

Also if you want to move everything from array b to a, emptying b in the process, you can do this:

while(b.length) {
  a.push(b.shift());
} 

and the result will be as follows:

a = [1, 2, 3, 4, 5, 6, 7];
b = [];

comments powered by Disqus