似乎没有办法用另一个数组扩展现有的JavaScript数组,即模仿Python的extend
方法。
我要实现以下目标:
>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
>>> a
[1, 2, 3, 4, 5]
我知道有一个a.concat(b)
方法,但是它创建了一个新数组,而不是简单地扩展第一个数组。我想要一种有效的算法,该算法在a
明显大于b
(即不复制a
)的情况下有效。
注意:这不是如何向数组追加内容的重复项。-这里的目标是将一个数组的全部内容添加到另一个数组中,并“就地”执行,即不复制扩展数组的所有元素。
该.push
方法可以采用多个参数。您可以使用传播运算符将第二个数组的所有元素作为参数传递给.push
:
>>> a.push(...b)
如果您的浏览器不支持ECMAScript 6,则可以.apply
改用:
>>> a.push.apply(a, b)
或者,如果您认为更清楚:
>>> Array.prototype.push.apply(a,b)
请注意,如果数组b
太长(麻烦开始于大约100,000个元素,具体取决于浏览器),所有这些解决方案将失败并出现堆栈溢出错误。
如果不能保证b
足够短,则应使用其他答案中所述的基于标准循环的技术。
更新2018年:一个更好的答案是我的一个更新:a.push(...b)
。不要再投票了,因为它从来没有真正回答过这个问题,但这是2015年Google首次点击时的黑客:)
对于那些仅搜索“ JavaScript array extension”并到达此处的用户,您可以很好地使用Array.concat
。
var a = [1, 2, 3];
a = a.concat([5, 4, 3]);
Concat将返回新数组的副本,因为线程启动器不需要。但是您可能并不在意(对于大多数用途,这肯定会很好)。
还有一些不错的ECMAScript 6糖,可以通过散布运算符的形式实现:
const a = [1, 2, 3];
const b = [...a, 5, 4, 3];
(它也会复制。)
您应该使用基于循环的技术。此页面上基于使用的其他答案.apply
可能无法用于大型阵列。
一个相当简洁的基于循环的实现是:
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);
}
然后,您可以执行以下操作:
var a = [1,2,3];
var b = [5,4,3];
a.extend(b);
.apply
当我们要追加的数组很大时(测试表明,对于我来说,大的在Chrome中大约大于150,000,在Firefox中大约大于500,000 ),DzinX的答案(使用push.apply)和其他基于方法的方法都会失败。您可以在此jsperf中看到此错误。
发生错误是因为在使用大数组作为第二个参数调用“ Function.prototype.apply”时超出了调用堆栈的大小。(MDN上有关于使用Function.prototype.apply超过调用堆栈大小的危险的注释-请参阅标题为“应用和内置函数”的部分。)
为了与本页面上的其他答案进行速度比较,请查看此jsperf(感谢EaterOfCode)。基于循环的实现在速度上与使用类似Array.push.apply
,但往往比慢一些Array.slice.apply
。
有趣的是,如果要追加的数组是稀疏的,则上述forEach
基于方法的方法可以利用稀疏性并胜过.apply
基于方法的方法。如果您想自己测试一下,请查看此jsperf。
顺便说一下,不要试图像我以前那样尝试将forEach实现进一步缩短为:
Array.prototype.extend = function (array) {
array.forEach(this.push, this);
}
因为这会产生垃圾结果!为什么?因为Array.prototype.forEach
为它调用的函数提供了三个参数-它们是:(element_value,element_index,source_array)。forEach
如果您使用“ forEach(this.push,this)” ,则所有这些都将在每次迭代时被推入您的第一个数组!
我觉得这几天最优雅的是:
arr1.push(...arr2);
关于传播运算符的MDN文章在ES2015(ES6)中提到了这种不错的含糖方式:
更好的推动
示例:push通常用于将数组推到现有数组的末尾。在ES5中,通常通过以下方式完成此操作:
var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; // Append all items from arr2 onto arr1 Array.prototype.push.apply(arr1, arr2);
在具有传播的ES6中,它变为:
var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; arr1.push(...arr2);
请注意,arr2
它不能很大(将其保留在大约100000个项目之内),因为根据jcdude的回答,调用堆栈会溢出。
首先apply()
在JavaScript中讲几句话,以帮助我们理解为什么使用它:
该
apply()
方法调用具有给定this
值的函数,并以数组形式提供参数。
推期望项目列表添加到数组。apply()
但是,该方法将函数调用的预期参数作为数组。这使我们可以push
使用内置push()
方法将一个数组的元素轻松转换为另一个数组。
假设您有以下数组:
var a = [1, 2, 3, 4];
var b = [5, 6, 7];
并简单地做到这一点:
Array.prototype.push.apply(a, b);
结果将是:
a = [1, 2, 3, 4, 5, 6, 7];
在ES6中,可以使用传播运算符(“ ...
”)来完成相同的操作,如下所示:
a.push(...b); //a = [1, 2, 3, 4, 5, 6, 7];
更短,更好,但目前尚未在所有浏览器中完全支持。
此外,如果你想移动一切从阵列b
到a
,排空b
的过程中,你可以这样做:
while(b.length) {
a.push(b.shift());
}
结果将如下所示:
a = [1, 2, 3, 4, 5, 6, 7];
b = [];
如果要使用jQuery,则有$ .merge()
例:
a = [1, 2];
b = [3, 4, 5];
$.merge(a,b);
结果:a = [1, 2, 3, 4, 5]
我喜欢a.push.apply(a, b)
上面描述的方法,如果需要,您可以随时创建一个库函数,如下所示:
Array.prototype.append = function(array)
{
this.push.apply(this, array)
}
像这样使用
a = [1,2]
b = [3,4]
a.append(b)
可以使用splice()
:
b.unshift(b.length)
b.unshift(a.length)
Array.prototype.splice.apply(a,b)
b.shift() // Restore b
b.shift() //
但是,尽管它比较丑陋,但速度并不比push.apply
Firefox 快,至少在Firefox 3.0中没有。
此解决方案对我有用(使用ECMAScript 6的传播运算符):
let array = ['my', 'solution', 'works'];
let newArray = [];
let newArray2 = [];
newArray.push(...array); // Adding to same array
newArray2.push([...array]); // Adding as child/leaf/sub-array
console.log(newArray);
console.log(newArray2);
您可以按照下面的方法创建一个polyfill进行扩展。它将添加到数组;就位并返回自身,以便可以链接其他方法。
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;
}
结合答案...
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]);
};
}
}
合并两个以上数组的另一种解决方案
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]);
}
}
};
然后调用并打印为:
mergeArrays(a, b, c);
console.log(a)
输出将是: Array [1, 2, 3, 4, 5, 6, 7]
答案非常简单。
>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
(The following code will combine the two arrays.)
a = a.concat(b);
>>> a
[1, 2, 3, 4, 5]
Concat的行为与JavaScript字符串串联非常相似。它将在调用函数的数组末尾返回您放入concat函数的参数的组合。问题是您必须将返回值分配给变量,否则它会丢失。所以举个例子
a.concat(b); <--- This does absolutely nothing since it is just returning the combined arrays, but it doesn't do anything with it.
使用Array.extend
的,而不是Array.push
为> 15万分的记录。
if (!Array.prototype.extend) {
Array.prototype.extend = function(arr) {
if (!Array.isArray(arr)) {
return this;
}
for (let record of arr) {
this.push(record);
}
return this;
};
}
您可以通过在push()
方法的帮助下将新元素简单地添加到数组中来实现。
let colors = ["Red", "Blue", "Orange"];
console.log('Array before push: ' + colors);
// append new value to the array
colors.push("Green");
console.log('Array after push : ' + colors);
用于将元素附加到数组开头的另一种方法是unshift()函数,该函数添加并返回新的长度。它接受多个参数,附加现有元素的索引,最后返回数组的新长度:
let colors = ["Red", "Blue", "Orange"];
console.log('Array before unshift: ' + colors);
// append new value to the array
colors.unshift("Black", "Green");
console.log('Array after unshift : ' + colors);
还有其他方法。您可以在此处查看它们。
超级简单,如果有问题,则无需依靠散布算子或应用。
b.map(x => a.push(x));
在对此进行了一些性能测试之后,它的运行速度非常慢,但是回答了有关不创建新阵列的问题。Concat的速度要快得多,即使是jQuery $.merge()
也可以做到。
文章标签:arrays , concatenation , javascript
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!
评论已关闭!