Copy Array Items into Another Array
I Have a Javascript Array dataArray Which I Want to Push into a New Array newArray. Except I Don't Want newArray[0] to Be dataArray. I Want to Push in All the...
I have a JavaScript array dataArray which I want to push into a new array newArray. Except I don't want newArray[0] to be dataArray. I want to push in all the items into the new array:
var newArray = [];
newArray.pushValues(dataArray1);
newArray.pushValues(dataArray2);
// ...
or even better:
var newArray = new Array (
dataArray1.values(),
dataArray2.values(),
// ... where values() (or something equivalent) would push the individual values into the array, rather than the array itself
);
So now the new array contains all the values of the individual data arrays. Is there some shorthand like pushValues available so I don't have to iterate over each individual dataArray, adding the items one by one?
18 Answers
Use the concat function, like so:
var arrayA = [1, 2];
var arrayB = [3, 4];
var newArray = arrayA.concat(arrayB);
The value of newArray will be [1, 2, 3, 4] (arrayA and arrayB remain unchanged; concat creates and returns a new array for the result).
In ECMAScript 6, you can use the Spread syntax:
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1.push(...arr2);
console.log(arr1)
Spread syntax is available in all major browsers (that excludes IE11). For the current compatibility, see this (continuously updated) compatibility table.
However, see Jack Giffin's reply below for more comments on performance. It seems concat is still better and faster than the spread operator.
Provided your arrays are not huge (see caveat below), you can use the push() method of the array to which you wish to append values. push() can take multiple parameters so you can use its apply() method to pass the array of values to be pushed as a list of function parameters. This has the advantage over using concat() of adding elements to the array in place rather than creating a new array.
However, it seems that for large arrays (of the order of 100,000 members or more), this trick can fail. For such arrays, using a loop is a better approach. See for details.
var newArray = [];
newArray.push.apply(newArray, dataArray1);
newArray.push.apply(newArray, dataArray2);
You might want to generalize this into a function:
function pushArray(arr, arr2) {
arr.push.apply(arr, arr2);
}
... or add it to Array's prototype:
Array.prototype.pushArray = function(arr) {
this.push.apply(this, arr);
};
var newArray = [];
newArray.pushArray(dataArray1);
newArray.pushArray(dataArray2);
... or emulate the original push() method by allowing multiple parameters using the fact that concat(), like push(), allows multiple parameters:
Array.prototype.pushArray = function() {
this.push.apply(this, this.concat.apply([], arguments));
};
var newArray = [];
newArray.pushArray(dataArray1, dataArray2);
Here's a loop-based version of the last example, suitable for large arrays and all major browsers, including IE <= 8:
Array.prototype.pushArray = function() {
var toPush = this.concat.apply([], arguments);
for (var i = 0, len = toPush.length; i < len; ++i) {
this.push(toPush[i]);
}
};
Found an elegant way from MDN
var vegetables = ['parsnip', 'potato'];
var moreVegs = ['celery', 'beetroot'];
// Merge the second array into the first one
// Equivalent to vegetables.push('celery', 'beetroot');
Array.prototype.push.apply(vegetables, moreVegs);
console.log(vegetables); // ['parsnip', 'potato', 'celery', 'beetroot']
Or you can use the spread operator feature of ES6:
let fruits = [ 'apple', 'banana'];
const moreFruits = [ 'orange', 'plum' ];
fruits.push(...moreFruits); // ["apple", "banana", "orange", "plum"]
The following seems simplest to me:
var newArray = dataArray1.slice();
newArray.push.apply(newArray, dataArray2);
As "push" takes a variable number of arguments, you can use the apply method of the push function to push all of the elements of another array. It constructs
a call to push using its first argument ("newArray" here) as "this" and the
elements of the array as the remaining arguments.
The slice in the first statement gets a copy of the first array, so you don't modify it.
Update If you are using a version of javascript with slice available, you can simplify the push expression to:
newArray.push(...dataArray2)
Must Read
๐ฅ๐ฒ๐๐ฒ๐ฎ๐ฟ๐ฐ๐ต ๐๐ป๐ฑ ๐๐ฒ๐ป๐ฐ๐ต๐บ๐ฎ๐ฟ๐ธ๐ ๐ฃ๐ผ๐๐ฒ๐ฟ๐ณ๐๐น๐น๐ ๐ฆ๐ต๐ผ๐ ๐ง๐ต๐ฎ๐ ๐๐ผ๐ป๐ฐ๐ฎ๐ ๐๐ ๐ง๐ต๐ฒ ๐๐ฒ๐๐ (for the original question)
For the facts, a performance test at jsperf and checking some things in the console are performed. For the research, the website irt.org is used. Below is a collection of all these sources put together plus an example function at the bottom.
โโโโโโโโโโโโโโโโโฆโโโโโโโฆโโโโโโโโโโโโโโโโโโฆโโโโโโโโโโโโโโโโฆโโโโโโโโโโฆโโโโโโโโโโโ โ Method โConcatโslice&push.apply โ push.apply x2 โ ForLoop โSpread โ โ โโโโโโโโโโโโโโโโฌโโโโโโโฌโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโโโโฃ โ mOps/Sec โ179 โ104 โ 76 โ 81 โ28 โ โ โโโโโโโโโโโโโโโโฌโโโโโโโฌโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโโโโฃ โ Sparse arrays โYES! โOnly the sliced โ no โ Maybe2 โno โ โ kept sparse โ โarray (1st arg) โ โ โ โ โ โโโโโโโโโโโโโโโโฌโโโโโโโฌโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโโโโฃ โ Support โMSIE 4โMSIE 5.5 โ MSIE 5.5 โ MSIE 4 โEdge 12 โ โ (source) โNNav 4โNNav 4.06 โ NNav 4.06 โ NNav 3 โMSIENNavโ โ โโโโโโโโโโโโโโโโฌโโโโโโโฌโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโโโโฃ โArray-like actsโno โOnly the pushed โ YES! โ YES! โIf have โ โlike an array โ โarray (2nd arg) โ โ โiterator1 โ โโโโโโโโโโโโโโโโโฉโโโโโโโฉโโโโโโโโโโโโโโโโโโฉโโโโโโโโโโโโโโโโฉโโโโโโโโโโฉโโโโโโโโโโโ 1 If the array-like object does not have a Symbol.iterator property, then trying to spread it will throw an exception. 2 Depends on the code. The following example code "YES" preserves sparseness.
function mergeCopyTogether(inputOne, inputTwo){
var oneLen = inputOne.length, twoLen = inputTwo.length;
var newArr = [], newLen = newArr.length = oneLen + twoLen;
for (var i=0, tmp=inputOne[0]; i !== oneLen; ++i) {
tmp = inputOne[i];
if (tmp !== undefined || inputOne.hasOwnProperty(i)) newArr[i] = tmp;
}
for (var two=0; i !== newLen; ++i, ++two) {
tmp = inputTwo[two];
if (tmp !== undefined || inputTwo.hasOwnProperty(two)) newArr[i] = tmp;
}
return newArr;
}
As seen above, I would argue that Concat is almost always the way to go for both performance and the ability to retain the sparseness of spare arrays. Then, for array-likes (such as DOMNodeLists like document.body.children), I would recommend using the for loop because it is both the 2nd most performant and the only other method that retains sparse arrays. Below, we will quickly go over what is meant by sparse arrays and array-likes to clear up confusion.