Javascript - insert an array inside another array

JavascriptArraysPerformance

Javascript Problem Overview


What is the more efficient way to insert an array inside another array.

a1 = [1,2,3,4,5];
a2 = [21,22];

newArray - a1.insertAt(2,a2) -> [1,2, 21,22, 3,4,5];

Iterating a2 using splice looks a bit awfull from a performance point of view if a2 array is large.

Thanks.

Javascript Solutions


Solution 1 - Javascript

You can use splice combined with some apply trickery:

a1 = [1,2,3,4,5];
a2 = [21,22];

a1.splice.apply(a1, [2, 0].concat(a2));

console.log(a1); // [1, 2, 21, 22, 3, 4, 5];

In ES2015+, you could use the spread operator instead to make this a bit nicer

a1.splice(2, 0, ...a2);

Solution 2 - Javascript

You can now do this if using ES2015 or later:

var a1 = [1,2,3,4,5];
var a2 = [21,22];
a1.splice(2, 0, ...a2);
console.log(a1) // => [1,2,21,22,3,4,5]

Refer to this for documenation on the spread (...) operator https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator

Solution 3 - Javascript

Had it wrong at first. Should have used concat() instead.

var a1 = [1,2,3,4,5],
    a2 = [21,22],
    startIndex = 0,
    insertionIndex = 2,
    result;    

result = a1.slice(startIndex, insertionIndex).concat(a2).concat(a1.slice(insertionIndex));

Example: http://jsfiddle.net/f3cae/1/

This expression uses slice(0, 2)[docs] to return the first two elements of a1 (where 0 is the starting index, and 2 is the element deleteCount, though a1 is not altered).

Intermediate result: [1,2]

It then uses concat(a2)[docs] to append a2 to the end of the [1,2].

Intermediate result:[1,2,21,22].

Next, a1.slice(2) is called within a trailing .concat() at the tail end of this expression, which amounts to [1,2,21,22].concat(a1.slice(2)).

A call to slice(2), having a positive integer argument, will return all elements after the 2nd element, counting by natural numbers (as in, there are five elements, so [3,4,5] will be returned from a1). Another way to say this is that the singular integer index argument tells a1.slice() at which position in the array to start returning elements from (index 2 is the third element).

Intermediate result: [1,2,21,22].concat([3,4,5])

Finally, the second .concat() adds [3,4,5] to the the end of [1,2,21,22].

Result: [1,2,21,22,3,4,5]

It may be tempting to alter Array.prototype, but one can simply extend the Array object using prototypal inheritance and inject said new object into your projects.

However, for those living on the edge ...

Example: http://jsfiddle.net/f3cae/2/

Array.prototype.injectArray = function( idx, arr ) {
    return this.slice( 0, idx ).concat( arr ).concat( this.slice( idx ) );
};

var a1 = [1,2,3,4,5];
var a2 = [21,22];

var result = a1.injectArray( 2, a2 );

Solution 4 - Javascript

The spread operator allows an expression to be expanded in places where multiple arguments (for function calls) or multiple elements (for array literals) are expected.

a2 = [21,22];
a1 = [1,2,...a2,3,4,5];//...a2 is use of spread operator
console.log(a1);

Solution 5 - Javascript

There are some truly creative answers to this question here. Here is a simple solution for those just starting out with arrays. It can be made to work all the way down to ECMAScript 3 compliant browsers, if desired.

Know something about splice before getting started.

Mozilla Developer Network: Array.prototype.splice()

First, understand two important forms of .splice().

let a1 = [1,2,3,4],
    a2 = [1,2];

Method 1) Remove x (deleteCount) elements, starting from a desired index.

let startIndex = 0, 
    deleteCount = 2;

a1.splice(startIndex, deleteCount); // returns [1,2], a1 would be [3,4]

Method 2) Remove elements after a desired start index to the end of the array.

a1.splice(2); // returns [3,4], a1 would be [1,2]

Using .splice(), a goal could be to split a1 into head and tail arrays by using one of the two forms above.

Using method #1, the return value would become the head, and a1 the tail.

let head = a1.splice(startIndex, deleteCount); // returns [1,2], a1 would be [3,4]

Now, in one fell swoop, concatenate the head, body (a2), and tail

[].concat(head, a2, a1);

Thus, this solution is more like the real world than any other presented thus far. Is this not what you would do with Legos? ;-) Here is a function, done using method #2.

/**
*@param target Array The array to be split up into a head and tail.
*@param body Array The array to be inserted between the head and tail.
*@param startIndex Integer Where to split the target array.
*/
function insertArray(target, body, startIndex)
{
    let tail = target.splice(startIndex); // target is now [1,2] and the head
    return [].concat(target, body, tail);
}

let newArray = insertArray([1, 2, 3, 4], ["a", "b"], 2); // [1, 2, "a", "b", 3, 4]

Shorter:

/**
*@param target Array The array to be split up into a head and tail.
*@param body Array The array to be inserted between the head and tail.
*@param startIndex Integer Where to split the target array.
*/
function insertArray(target, body, startIndex)
{
    return [].concat(target, body, target.splice(startIndex));
}

Safer:

/**
*@param target Array The array to be split up into a head and tail.
*@param body Array The array to be inserted between the head and tail.
*@param startIndex Integer Where to split the target array.
*@throws Error The value for startIndex must fall between the first and last index, exclusive.
*/
function insertArray(target, body, startIndex)
{
    const ARRAY_START = 0,
          ARRAY_END = target.length - 1,
          ARRAY_NEG_END = -1,
          START_INDEX_MAGNITUDE = Math.abs(startIndex);

    if (startIndex === ARRAY_START) {
        throw new Error("The value for startIndex cannot be zero (0).");
    }

    if (startIndex === ARRAY_END || startIndex === ARRAY_NEG_END) {
        throw new Error("The startIndex cannot be equal to the last index in target, or -1.");
    }

    if (START_INDEX_MAGNITUDE >= ARRAY_END) {
        throw new Error("The absolute value of startIndex must be less than the last index.");
    }

    return [].concat(target, body, target.splice(startIndex));
}

The advantages of this solution include:

  1. A simple premise dominates the solution--fill an empty array.

  2. Head, body, and tail nomenclature feels natural.

  3. No double call to .slice(). No slicing at all.

  4. No .apply(). Highly unnecessary.

  5. Method chaining is avoided.

  6. Works in ECMAScript 3 and 5 simply by using var instead of let or const.

**7) Ensures that there will be a head and tail to slap on to the body, unlike many other solutions presented. If you are adding an array before, or after, the bounds, you should at least be using .concat()!!!!

Note: Use of the spread opearator ... makes all of this much easier to accomplish.

Solution 6 - Javascript

I wanted to find a way to do this with splice() and no iterating: http://jsfiddle.net/jfriend00/W9n27/.

a1 = [1,2,3,4,5];
a2 = [21,22];

a2.unshift(2, 0);          // put first two params to splice onto front of array
a1.splice.apply(a1, a2);   // pass array as arguments parameter to splice
console.log(a1);           // [1, 2, 21, 22, 3, 4, 5];

In general purpose function form:

function arrayInsertAt(destArray, pos, arrayToInsert) {
    var args = [];
    args.push(pos);                           // where to insert
    args.push(0);                             // nothing to remove
    args = args.concat(arrayToInsert);        // add on array to insert
    destArray.splice.apply(destArray, args);  // splice it in
}

Solution 7 - Javascript

var a1 = [1,2,3,4,5];
var a2 = [21,22];
	
function injectAt(d, a1, a2) {
    for(var i=a1.length-1; i>=d; i--) {
        a1[i + a2.length] = a1[i];
    }
    for(var i=0; i<a2.length; i++) {
        a1[i+d] = a2[i];
    }
}
	
injectAt(2, a1, a2);
	
alert(a1);

Solution 8 - Javascript

Here's my version with no special tricks:

function insert_array(original_array, new_values, insert_index) {
	for (var i=0; i<new_values.length; i++) {
		original_array.splice((insert_index + i), 0, new_values[i]);
	}
	return original_array;
}

Solution 9 - Javascript

If you want to insert another array into an array without creating a new one, the easiest way is to use either push or unshift with apply

Eg:

a1 = [1,2,3,4,5];
a2 = [21,22];

// Insert a1 at beginning of a2
a2.unshift.apply(a2,a1);
// Insert a1 at end of a2
a2.push.apply(a2,a1);

This works because both push and unshift take a variable number of arguments. A bonus, you can easily choose which end to attach the array from!

Solution 10 - Javascript

As mentioned in another thread,the answers above will not work in very large arrays (200K elements). See alternate answer here involving splice and manual push: https://stackoverflow.com/a/41465578/1038326

Array.prototype.spliceArray = function(index, insertedArray) {
    var postArray = this.splice(index);
    inPlacePush(this, insertedArray);
    inPlacePush(this, postArray);

    function inPlacePush(targetArray, pushedArray) {
  // Not using forEach for browser compatability
        var pushedArrayLength = pushedArray.length;
        for (var index = 0; index < pushedArrayLength; index++) {
           targetArray.push(pushedArray[index]);
       }
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionic3View Question on Stackoverflow
Solution 1 - JavascriptnickfView Answer on Stackoverflow
Solution 2 - JavascriptElmerView Answer on Stackoverflow
Solution 3 - Javascriptuser113716View Answer on Stackoverflow
Solution 4 - JavascriptHikmat SijapatiView Answer on Stackoverflow
Solution 5 - JavascriptAnthony RutledgeView Answer on Stackoverflow
Solution 6 - Javascriptjfriend00View Answer on Stackoverflow
Solution 7 - JavascriptBhesh GurungView Answer on Stackoverflow
Solution 8 - JavascriptarlomediaView Answer on Stackoverflow
Solution 9 - JavascriptRangerMauveView Answer on Stackoverflow
Solution 10 - JavascriptGabriel KohenView Answer on Stackoverflow