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

时间:2011-08-11 20:41:19

标签: javascript arrays performance

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

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

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

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

感谢。

10 个答案:

答案 0 :(得分:149)

您可以使用splice结合某些apply技巧:

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

答案 1 :(得分:13)

一开始就错了。应该使用concat()代替。

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

示例: http://jsfiddle.net/f3cae/1/

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

中级结果a1

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

中级结果[1,2]

接下来,[1,2,21,22]在此表达式尾部的尾随a1.slice(2)内调用,相当于.concat()

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

中级结果a1.slice()

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

结果[1,2,21,22]

改变[1,2,21,22,3,4,5]可能很诱人,但可以使用原型继承扩展Array对象并将所述新对象注入到项目中。

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

示例: http://jsfiddle.net/f3cae/2/

Array.prototype

答案 2 :(得分:9)

如果使用ES2015或更高版本,现在可以执行此操作:

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]

有关spread(...)运算符https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator

的文档,请参阅此处

答案 3 :(得分:2)

我希望找到一种方法,使用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
}

答案 4 :(得分:2)

spread运算符允许在需要多个参数(用于函数调用)或多个元素(用于数组文字)的位置扩展表达式。

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

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

答案 7 :(得分:0)

如果要在不创建新数组的情况下将另一个数组插入数组,最简单的方法是使用pushunshift 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都采用了可变数量的参数。 奖金,您可以轻松选择从哪个端点附加阵列!

答案 8 :(得分:0)

如另一个帖子所述,上面的答案不适用于非常大的数组(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]);
       }
    }
}

答案 9 :(得分:0)

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

开始使用之前,请先了解一些有关拼接的知识。

Mozilla Developer Network: Array.prototype.splice()

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

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

方法1)从所需的索引处删除x(deleteCount)个元素。

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,返回值将成为头部,a1将成为尾部。

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)不能双重呼叫.slice()。完全没有切片。

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

5)避免方法链接。

6)只需使用var而不是letconst,即可在ECMAScript 3和5中工作。

** 7)确保将头和尾巴拍打到身体上,这与提出的许多其他解决方案不同。如果要在边界之前或之后添加数组,则至少应使用.concat() !!!!

请注意:使用扩散人工监督者...使所有这些工作变得更加容易。