Javascript-在另一个数组中插入一个数组

在另一个数组中插入数组的更有效的方法是什么。

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


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

如果 a2数组很大,那么从性能角度来看,使用拼接来迭代 a2看起来有点糟糕。

谢谢。

124785 次浏览

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));

示例: < a href = “ http://jsfiddle.net/f3cae/1/”rel = “ nofollow noReferrer”> http://jsfiddle.net/f3cae/1/

这个表达式使用 slice(0, 2)[docs]返回 a1的前两个元素(其中 0是起始索引,2是元素 delete teCount,尽管 a1没有改变)。

中间结果 : [1,2]

然后它使用 concat(a2) < sup > < i > [ docs ] a2附加到 [1,2]的末尾。

中间结果 : [1,2,21,22]

接下来,在这个表达式末尾的后跟 .concat()中调用 a1.slice(2),这相当于 [1,2,21,22].concat(a1.slice(2))

对具有正整数参数的 slice(2)的调用将返回第2个元素之后的所有元素,并按自然数进行计数(因为有5个元素,所以 [3,4,5]将从 a1返回)。另一种说法是,单数整数索引参数告诉 a1.slice()在数组中的哪个位置开始返回元素(索引2是第三个元素)。

中间结果 : [1,2,21,22].concat([3,4,5])

最后,第二个 .concat()[3,4,5]添加到 [1,2,21,22]的末尾。

结果 : [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.

然而,对于那些生活在边缘的人来说..。

示例: < a href = “ http://jsfiddle.net/f3cae/2/”rel = “ nofollow noReferrer”> 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 );

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];

在 ES2015 + 中,您可以使用扩展运算符来使其更好一些

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

我想找到一种方法来做到这一点与 splice()和没有迭代: 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];

一般用途函数形式:

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
}
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);

这是我的版本,没有什么特别的技巧:

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;
}

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

例如:

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);

这是可行的,因为 pushunshift都采用数量可变的参数。 额外的好处是,你可以轻松地选择从哪一端附加数组!

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]

有关扩展(...)操作符 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator的文档,请参阅此文档

正如在另一个线程中提到的,上面的答案在非常大的数组(200K 元素)中不起作用。参见这里涉及拼接和手动推动的替代答案: 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]);
}
}
}

spread操作符允许在需要多个参数(对于函数调用)或多个元素(对于数组文字)的地方展开表达式。

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

这里有一些真正有创意的答案来回答这个问题。对于那些刚刚开始使用数组的人来说,这里有一个简单的解决方案。如果需要的话,它可以一直工作到兼容 ECMAScript 3的浏览器。

在开始之前了解一些关于拼接的知识。

Mozilla Developer Network: array.Prototype.splice ()

首先,了解 .splice()的两种重要形式。

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

方法1)从所需的索引开始,删除 x (delete teCount)元素。

let startIndex = 0,
deleteCount = 2;


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

方法2)在数组末尾的期望开始索引后删除元素。

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

使用 .splice(),目标可以是通过使用上述两种形式之一将 a1分割为头部和尾部数组。

使用方法 # 1,返回值将成为 head,而 a1将成为 tail。

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

现在,一下子连接头部、身体(a2)和尾巴

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

因此,这个解决方案比迄今为止提出的任何其他解决方案都更像现实世界。这不就是你用乐高玩具做的事吗?下面是一个函数,使用方法 # 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]

简短:

/**
*@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));
}

更安全:

/**
*@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));
}

这种解决办法的好处包括:

1)一个简单的前提支配着解决方案——填充一个空数组。

2)头,身体和尾巴的命名感觉很自然。

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

4)没有 .apply()完全没有必要。

5)避免方法链接。

6)使用 var代替 letconst在 ECMAScript 3和5中工作。

7)确保有一个头和一个尾巴拍打在身体上,不像其他许多解决方案。如果您在边界之前或之后添加数组,那么您至少应该使用 .concat()! ! ! !

注意: 使用扩展运算符 ...使得所有这些更容易实现。

小心使用扩展运算符,例如,您需要像下面这样在数组中插入大量项

let C = [];


for(let i=0;i<200000;i++){
C.push(i);
}


let A = [1,2,3,4,5];


A.splice(2,0,...C); //this will cause RangeError: Maximum call stack size exceeded

因为,展开运算符将数组中的项拆分为展开变量,并将它们传递给拼接方法。

扩展操作符有 N 项的限制(在 Visual Code 中,我意识到 N 大约是120000)

确保没有错误发生的实用方法(我在我的实际项目中使用了超过200000个项目)

const N = 120000;


function insertArray(origin,index,inserted){


if(inserted.length>N){


if(index>0 && index<origin.length-1){


const chunk1 = origin.slice(0,index);


const chunk2 = origin.slice(index);


return [].concat(chunk1,inserted,chunk2);


}else{
return null;
}


}else{


return origin.splice(index,0,...inserted);


}


}