Javascript 将数组项复制到另一个数组中

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4156101/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 11:09:03  来源:igfitidea点击:

Copy array items into another array

javascriptarrays

提问by bba

I have a JavaScript array dataArraywhich 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:

我有一个 JavaScript 数组dataArray,我想将它推入一个新数组newArray。除了我不想newArray[0]成为dataArray。我想将所有项目推入新数组:

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 pushValuesavailable so I don't have to iterate over each individual dataArray, adding the items one by one?

所以现在新数组包含各个数据数组的所有值。是否有一些类似的速记,pushValues这样我就不必遍历每个人dataArray,逐个添加项目?

回答by WiseGuyEh

Use the concatfunction, like so:

使用concat函数,如下所示:

var arrayA = [1, 2];
var arrayB = [3, 4];
var newArray = arrayA.concat(arrayB);

The value of newArraywill be [1, 2, 3, 4](arrayAand arrayBremain unchanged; concatcreates and returns a new array for the result).

newArraywill的值是[1, 2, 3, 4](arrayAarrayB保持不变;concat为结果创建并返回一个新数组)。

回答by Tim Down

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.

如果您的数组不是很大(请参阅下面的警告),您可以使用push()要附加值的数组的方法。push()可以采用多个参数,因此您可以使用其apply()方法将要推送的值数组作为函数参数列表传递。与使用concat()将元素添加到数组中而不是创建新数组相比,这具有优势。

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 https://stackoverflow.com/a/17368101/96100for details.

但是,对于大型数组(100,000 名或更多成员的数量级),此技巧似乎会失败。对于此类数组,使用循环是更好的方法。有关详细信息,请参阅https://stackoverflow.com/a/17368101/96100

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的原型中:

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:

... 或push()通过使用允许多个参数的事实来模拟原始方法concat(),例如push(),允许多个参数:

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:

这是上一个示例的基于循环的版本,适用于大型数组和所有主流浏览器,包括 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]);
    }
};

回答by Karel Bílek

I will add one more "future-proof" reply

我会再添加一个“面向未来”的回复

In ECMAScript 6, you can use the Spread syntax:

在 ECMAScript 6 中,您可以使用Spread 语法

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

console.log(arr1)

Spread syntax is not yet included in all major browsers. For the current compatibility, see this (continuously updated) compatibility table.

Spread 语法尚未包含在所有主要浏览器中。有关当前的兼容性,请参阅此(不断更新的)兼容性表

You can, however, use spread syntax with Babel.js.

但是,您可以在Babel.js 中使用扩展语法。

edit:

编辑:

See Hyman Giffin's reply below for more comments on performance. It seems concat is still better and faster than spread operator.

有关性能的更多评论,请参阅下面 Hyman Giffin 的回复。似乎 concat 仍然比扩展运算符更好更快。

回答by Believe2014

Found an elegant way from MDN

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 operatorfeature of ES6:

或者你可以使用spread operatorES6的特性:

let fruits = [ 'apple', 'banana'];
const moreFruits = [ 'orange', 'plum' ];

fruits.push(...moreFruits); // ["apple", "banana", "orange", "plum"]

回答by shaunc

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 applymethod of the pushfunction 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.

由于“push”接受可变数量的参数,因此您可以使用applypush函数的方法来推送另一个数组的所有元素。它使用第一个参数(此处为“newArray”)作为“this”,将数组元素作为剩余参数构造一个 push 调用。

The slicein the first statement gets a copy of the first array, so you don't modify it.

slice一个语句中的 获取第一个数组的副本,因此您不要修改它。

UpdateIf you are using a version of javascript with slice available, you can simplify the pushexpression to:

更新如果您使用的是切片可用的 javascript 版本,您可以将push表达式简化为:

newArray.push(...dataArray2)

回答by Sébastien VINCENT

var a=new Array('a','b','c');
var b=new Array('d','e','f');
var d=new Array('x','y','z');
var c=a.concat(b,d)

Does that solve your problem ?

这能解决你的问题吗?

回答by Panos Theof

The function below doesn't have an issue with the length of arrays and performs better than all suggested solutions:

下面的函数没有数组长度问题,并且比所有建议的解决方案执行得更好:

function pushArray(list, other) {
    var len = other.length;
    var start = list.length;
    list.length = start + len;
    for (var i = 0; i < len; i++ , start++) {
        list[start] = other[i];
    }
}

unfortunately, jspref refuses to accept my submissions, so here they are the results using benchmark.js

不幸的是,jspref 拒绝接受我的提交,所以这里是使用 benchmark.js 的结果

        Name            |   ops/sec   |  ± %  | runs sampled
for loop and push       |      177506 |  0.92 | 63
Push Apply              |      234280 |  0.77 | 66
spread operator         |      259725 |  0.40 | 67
set length and for loop |      284223 |  0.41 | 66

where

在哪里

for loop and push is:

for 循环和 push 是:

    for (var i = 0, l = source.length; i < l; i++) {
        target.push(source[i]);
    }

Push Apply:

推送应用:

target.push.apply(target, source);

spread operator:

展开运算符:

    target.push(...source);

and finally the 'set length and for loop' is the above function

最后“设置长度和循环”是上面的函数

回答by Hyman Giffin

For the facts, a performance test at jsperfand checking some things in the console are performed. For the research, the website irt.orgis used. Below is a collection of all these sources put together plus an example function at the bottom.

事实上,在 jsperf 上进行性能测试并在控制台中检查了一些东西。研究使用了网站 irt.org。下面是所有这些源的集合以及底部的示例函数。

╔═══════════════╦══════╦═════════════════╦═══════════════╦═════════╦══════════╗
║ 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  ║MSIE NNav ║
╠═══════════════╬══════╬═════════════════╬═══════════════╬═════════╬══════════╣
║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.

如上所述,我认为 Concat 几乎总是兼顾性能和保留备用阵列稀疏性的能力。然后,对于类数组(例如 DOMNodeLists like document.body.children),我建议使用 for 循环,因为它是性能第二高的方法,也是唯一保留稀疏数组的其他方法。下面,我们将快速了解稀疏数组和类似数组的含义以消除混淆。

At first, some people may think that this is a fluke and that browser vendors will eventually get around to optimizing Array.prototype.push to be fast enough to beat Array.prototype.concat. WRONG! Array.prototype.concat will always be faster (in principle at least) because it is a simple copy-n-paste over the data. Below is a simplified persuado-visual diagram of what a 32-bit array implementation might look like (please note real implementations are a LOT more complicated)

起初,有些人可能认为这是侥幸,浏览器供应商最终会开始优化 Array.prototype.push 以使其足够快以击败 Array.prototype.concat。错误的!Array.prototype.concat 总是更快(至少原则上是这样),因为它是对数据的简单复制粘贴。下面是 32 位数组实现可能是什么样子的简化说服视觉图(请注意,实际实现要复杂得多)

Byte ║ Data here
═════╬═══════════
0x00 ║ int nonNumericPropertiesLength = 0x00000000
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int length = 0x00000001
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int valueIndex = 0x00000000
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int valueType = JS_PRIMITIVE_NUMBER
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ uintptr_t valuePointer = 0x38d9eb60 (or whereever it is in memory)
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid

As seen above, all you need to do to copy something like that is almost as simple as copying it byte for byte. With Array.prototype.push.apply, it is a lot more than a simple copy-n-paste over the data. The ".apply" has to check each index in the array and convert it to a set of arguments before passing it to Array.prototype.push. Then, Array.prototype.push has to additionally allocate more memory each time, and (for some browser implementations) maybe even recalculate some position-lookup data for sparseness.

如上所示,复制类似内容所需要做的几乎就像逐字节复制一样简单。使用 Array.prototype.push.apply,它不仅仅是对数据进行简单的复制粘贴。“.apply”必须检查数组中的每个索引并将其转换为一组参数,然后再将其传递给 Array.prototype.push。然后, Array.prototype.push 每次必须额外分配更多内存,并且(对于某些浏览器实现)甚至可能重新计算一些位置查找数据以进行稀疏化。

An alternative way to think of it is this. The source array one is a large stack of papers stapled together. The source array two is also another large stack of papers. Would it be faster for you to

另一种思考方式是这样。源阵列一是一大堆装订在一起的纸。源阵二也是一大叠纸。你会更快吗

  1. Go to the store, buy enough paper needed for a copy of each source array. Then put each source array stacks of paper through a copy-machine and staple the resulting two copies together.
  2. Go to the store, buy enough paper for a single copy of the first source array. Then, copy the source array to the new paper by hand, ensuring to fill in any blank sparse spots. Then, go back to the store, buy enough paper for the second source array. Then, go through the second source array and copy it while ensuring no blank gaps in the copy. Then, staple all the copied papers together.
  1. 去商店,购买足够的纸张来复制每个源阵列。然后将每个源阵列的纸叠放在复印机中,并将生成的两份副本装订在一起。
  2. 去商店,购买足够的纸来制作第一个源阵列的单个副本。然后,手动将源数组复制到新纸上,确保填充任何空白的稀疏点。然后,返回商店,为第二个源阵列购买足够的纸张。然后,遍历第二个源数组并复制它,同时确保副本中没有空白。然后,将所有复印的纸张装订在一起。

In the above analogy, option #1 represents Array.prototype.concat while #2 represents Array.prototype.push.apply. Let us test this out with a similar JSperf differing only in that this one tests the methods over sparse arrays, not solid arrays. One can find it right here.

在上面的类比中,选项 #1 代表 Array.prototype.concat 而 #2 代表 Array.prototype.push.apply。让我们用一个类似的 JSperf 来测试一下,不同之处仅在于这个 JSperf 测试稀疏数组上的方法,而不是实体数组。人们可以在这里找到它。

Therefore, I rest my case that the future of performance for this particular use case lies not in Array.prototype.push, but rather in Array.prototype.concat.

因此,我认为这个特定用例的性能未来不在于 Array.prototype.push,而在于 Array.prototype.concat。

When certain members of the array are simply missing. For example:

当数组的某些成员完全丢失时。例如:

// This is just as an example. In actual code, 
// do not mix different types like this.
var mySparseArray = [];
mySparseArray[0] = "foo";
mySparseArray[10] = undefined;
mySparseArray[11] = {};
mySparseArray[12] =  10;
mySparseArray[17] = "bar";
console.log("Length:   ", mySparseArray.length);
console.log("0 in it:  ", 0 in mySparseArray);
console.log("arr[0]:   ", mySparseArray[0]);
console.log("10 in it: ", 10 in mySparseArray);
console.log("arr[10]   ", mySparseArray[10]);
console.log("20 in it: ", 20 in mySparseArray);
console.log("arr[20]:  ", mySparseArray[20]);

Alternatively, javascript allows you to initialize spare arrays easily.

或者,javascript 允许您轻松初始化备用阵列。

var mySparseArray = ["foo",,,,,,,,,,undefined,{},10,,,,,"bar"];

-

——

An array-like is an object that has at least a lengthproperty, but was not initialized with new Arrayor []; For example, the below objects are classified as array-like.

类数组是至少具有length属性但未使用new Array或初始化的对象[];例如,以下对象被归类为类数组。

{0: "foo", 1: "bar", length:2}
document.body.children
new Uint8Array(3)
  • This is array-like because although it's a(n) (typed) array, coercing it to an array changes the constructor.
  • 这是类数组,因为尽管它是一个(n)(类型化)数组,但将其强制转换为数组会更改构造函数。
(function(){return arguments})()

Observe what happens using a method that does coerce array-likes into arrays like slice.

观察使用将类似数组的内容强制转换为类似切片的数组的方法会发生什么。

var slice = Array.prototype.slice;
// For arrays:
console.log(slice.call(["not an array-like, rather a real array"]));
// For array-likes:
console.log(slice.call({0: "foo", 1: "bar", length:2}));
console.log(slice.call(document.body.children));
console.log(slice.call(new Uint8Array(3)));
console.log(slice.call( function(){return arguments}() ));

  • NOTE:It is bad practice to call slice on function arguments because of performance.
  • 注意:由于性能原因,在函数参数上调用 slice 是不好的做法。

Observe what happens using a method that does notcoerce array-likes into arrays like concat.

观察使用,它的方法发生了什么强制阵列喜欢到像CONCAT阵列。

var empty = [];
// For arrays:
console.log(empty.concat(["not an array-like, rather a real array"]));
// For array-likes:
console.log(empty.concat({0: "foo", 1: "bar", length:2}));
console.log(empty.concat(document.body.children));
console.log(empty.concat(new Uint8Array(3)));
console.log(empty.concat( function(){return arguments}() ));

回答by Black Mamba

Here's the ES6 way

这是 ES6 的方式

var newArray = [];
let dataArray1 = [1,2,3,4]
let dataArray2 = [5,6,7,8]
newArray = [...dataArray1, ...dataArray2]
console.log(newArray)

The above method is good to go for most of the cases and the cases it is not please consider concat, like you have hundred thousands of items in arrays.

上述方法适用于大多数情况,而不是请考虑的情况concat,例如您在数组中有数十万个项目。

    let dataArray1 = [1,2,3,4]
    let dataArray2 = [5,6,7,8]
    let newArray = dataArray1.concat(dataArray2);
    console.log(newArray)

回答by Ryan H.

With JavaScript ES6, you can use the ... operator as a spread operator which will essentially convert the array into values. Then, you can do something like this:

在 JavaScript ES6 中,您可以将 ... 运算符用作扩展运算符,该运算符基本上会将数组转换为值。然后,您可以执行以下操作:

const myArray = [1,2,3,4,5];
const moreData = [6,7,8,9,10];

const newArray = [
  ...myArray,
  ...moreData,
];

While the syntax is concise, I do not know how this works internally and what the performance implications are on large arrays.

虽然语法简洁,但我不知道它在内部是如何工作的,以及对大型数组的性能影响是什么。