49

I want to replace elements in some array from 0 element, with elements of another array with variable length. Like:

var arr = new Array(10), anotherArr = [1, 2, 3], result;
result = anotherArr.concat(arr);
result.splice(10, anotherArr.length);

Is there some better way?

Zach
  • 539
  • 1
  • 4
  • 22
Artem Svirskyi
  • 7,305
  • 7
  • 31
  • 43

7 Answers7

63

You can use the splice method to replace part of an array with items from another array, but you have to call it in a special way as it expects the items as parameters, not the array.

The splice method expects parameters like (0, anotherArr.Length, 1, 2, 3), so you need to create an array with the parameters and use the apply method to call the splice method with the parameters:

Array.prototype.splice.apply(arr, [0, anotherArr.length].concat(anotherArr));

Example:

var arr = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
var anotherArr = [ 1, 2, 3 ];

Array.prototype.splice.apply(arr, [0, anotherArr.length].concat(anotherArr));

console.log(arr);

Output:

[ 1, 2, 3, 'd', 'e', 'f', 'g', 'h', 'i', 'j']

Demo: http://jsfiddle.net/Guffa/bB7Ey/

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • 4
    If the first array is longer than the replacement the above solution won't remove the extra elements on the end. This slight modification will: Array.prototype.splice.apply(arr, [0, arr.length].concat(anotherArr)); – Loren_ Oct 20 '16 at 00:21
  • @perilandmishap: Yes, that was the point. If you want to replace the array you can just replace the entire object: `arr = anotherArr;`. – Guffa Oct 29 '16 at 14:39
  • 1
    In Flux/Redux style state managers frequently you're working with a const and not permitted to change the reference to your object, so just doing reassignment isn't an option. It's a silly problem to have, but the state of javascript is a little silly at the moment. – Loren_ Feb 20 '17 at 20:50
59

In ES6 with a single operation, you can do this to replace the first b.length elements of a with elements of b:

let a = [1,  2,  3,  4,  5]
let b = [10, 20, 30]

a.splice(0, b.length, ...b)

console.log(a) // -> [10, 20, 30, 4, 5]

It could be also useful to replace the entire content of an array, using a.length (or Infinity) in the splice length:

let a = [1,  2,  3,  4,  5]
let b = [10, 20, 30]

a.splice(0, a.length, ...b)
// or
// a.splice(0, Infinity, ...b)

console.log(a) // -> [10, 20, 30], which is the content of b

The a array's content will be entirely replaced by b content.

Note 1: in my opinion the array mutation should only be used in performance-critical applications, such as high FPS animations, to avoid creating new arrays. Normally I would create a new array maintaining immutability.

Note 2: if b is a very large array, this method is discouraged, because ...b is being spread in the arguments of splice, and there's a limit on the number of parameters a JS function can accept. In that case I encourage to use another method (or create a new array, if possible!).

caesarsol
  • 2,010
  • 1
  • 20
  • 21
  • Nice solution! This is better than the one involving `length` because I can also map over the same array. E.g. `let a = [5, 6, 7, 8]; a.splice(0, a.length, ...a.map(x => x * x));` And it doesn't require reassignment to `a` either. – nils May 12 '17 at 06:13
  • 4
    Just use `a.splice(0, Infinity, ...b)`. The second arguments is irrelevant as long as it's larger than the number of elements to be removed. – GOTO 0 May 31 '17 at 08:22
  • 2
    Nice, but the initial question was how to replace part of the first array. It should be `a.splice(0, b.length, ...b)` - with length of b measured instead. It will work correctly with any lengths of both arrays – Sergey Nudnov Mar 20 '19 at 18:55
  • 1
    This is *v* slow for large arrays and can end up in `Maximum recursion depth exceeced` – WestCoastProjects Aug 21 '20 at 23:59
  • 1
    @javadba that's right, for very large arrays I think you should create a new array. I believe the cycling time does overcome the creation time. (anyway, the `Maximum recursion` error is quite cryptic... There's no recursion in that code, and I think there is never any recursion in browser implementations) – caesarsol Aug 25 '20 at 18:12
  • 1
    @javadba I added a Note 2 to give this warning! thanks. – caesarsol Aug 25 '20 at 18:19
13

In ES6, TypeScript, Babel or similar you can just do:

arr1.length = 0; // Clear your array
arr1.push(...arr2); // Push the second array using the spread opperator

Simple.

Kesarion
  • 2,808
  • 5
  • 31
  • 52
  • 1
    Simlpe, but what if its a associative array? – Tim Bogdanov Oct 20 '21 at 20:49
  • @TimBogdanov JS does not have associate arrays, you may be thinking of a an `Object` used as an `Array` (and an `Array` is an `Object` and can double in this role, but it's unorthodox and unadvised), or the newer `Map` object. – ken Sep 26 '22 at 16:29
7

For anyone looking for a way to replace the entire contents of one array with entire contents of another array while preserving the original array:

Array.prototype.replaceContents = function (array2) {
    //make a clone of the 2nd array to avoid any referential weirdness
    var newContent = array2.slice(0);
    //empty the array
    this.length = 0;
    //push in the 2nd array
    this.push.apply(this, newContent);
};

The prototype function takes an array as a parameter which will serve as the new array content, clones it to avoid any weird referential stuff, empties the original array, and then pushes in the passed in array as the content. This preserves the original array and any references.

Now you can simply do this:

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

I know this is not strictly what the initial question was asking, but this question comes up first when you search in google, and I figured someone else may find this helpful as it was the answer I needed.

Matthew Goodwin
  • 1,162
  • 12
  • 16
3

You can just use splice, can add new elements while removing old ones:

var arr = new Array(10), anotherArr = [1, 2, 3];

arr.splice.apply(arr, [0, anotherArr.length].concat(anotherArr))

If you don't want to modify the arr array, you can use slice that returns a shallow copy of the array:

var arr = new Array(10), anotherArr = [1, 2, 3], result = arr.slice(0);

result.splice.apply(result, [0, anotherArr.length].concat(anotherArr));

Alternatively, you can use slice to cut off the first elements and adding the anotherArr on top:

result = anotherArr.concat(arr.slice(anotherArr.length));
ZER0
  • 24,846
  • 5
  • 51
  • 54
1

I'm not sure if it's a "better" way, but at least it allows you to choose the starting index (whereas your solution only works starting at index 0). Here's a fiddle.

// Clone the original array
var result = arr.slice(0);
// If original array is no longer needed, you can do with:
// var result = arr;

// Remove (anotherArr.length) elements starting from index 0
// and insert the elements from anotherArr into it
Array.prototype.splice.apply(result, [0, anotherArr.length].concat(anotherArr));

(Damnit, so many ninjas. :-P)

Mattias Buelens
  • 19,609
  • 4
  • 45
  • 51
1

You can just set the length of the array in this case. For more complex cases see @Guffa's answer.

var a = [1,2,3];
a.length = 10;
a; // [1, 2, 3, undefined x 7]
1983
  • 5,882
  • 2
  • 27
  • 39