web-dev-qa-db-ja.com

Javascript-別の配列内に配列を挿入します

別の配列内に配列を挿入するより効率的な方法は何ですか。

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

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

スプライスを使用したa2の反復は、a2配列が大きい場合、パフォーマンスの観点からは少しひどく見えます。

ありがとう。

76
ic3

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

最初は間違っていました。代わりに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)を使用します[ドキュメント]a1の最初の2つの要素を返します(0は開始インデックス、2は要素deleteCountですが、a1は変更されません)。

中間結果[1,2]

次に、 concat(a2)を使用します[ドキュメント]a2の末尾に[1,2]を追加します。

中間結果[1,2,21,22]

次に、a1.slice(2)が、この式の末尾の末尾の.concat()内で呼び出されます。これは[1,2,21,22].concat(a1.slice(2))になります。

正の整数引数を持つslice(2)の呼び出しは、自然数でカウントして2番目の要素の後のすべての要素を返します(5つの要素があるため、[3,4,5]a1から返されます)。別の言い方をすると、特異な整数のインデックス引数は、a1.slice()に配列のどの位置から要素を返し始めるかを指示します(インデックス2は3番目の要素です)。

中間結果[1,2,21,22].concat([3,4,5])

最後に、2番目の.concat()[3,4,5][1,2,21,22]の最後に追加します。

結果[1,2,21,22,3,4,5]

Array.prototypeを変更したくなるかもしれませんが、プロトタイプの継承を使用してArrayオブジェクトを単純に拡張し、その新しいオブジェクトをプロジェクトに注入できます。

しかし、エッジに住んでいる人のために...

例: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 );
13
user113716

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]

スプレッド(...)演算子については、こちらを参照してください https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator

10
Elmer

spread 演算子を使用すると、複数の引数(関数呼び出しの場合)または複数の要素(配列リテラルの場合)が予想される場所で式を展開できます。

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

私は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
}
2
jfriend00

この質問に対する真に独創的な答えがここにあります。配列から始めたばかりの人向けの簡単なソリューションを次に示します。必要に応じて、ECMAScript 3準拠のブラウザーまでずっと機能するようにできます。

始める前にスプライスについて何かを知ってください。

Mozilla Developer Network:Array.prototype.splice()

まず、.splice()の2つの重要な形式を理解します。

_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()を使用すると、上記の2つの形式のいずれかを使用して、_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)ECMAScript 3および5では、varまたはletの代わりにconstを使用するだけで機能します。

** 7)提示されている他の多くのソリューションとは異なり、身体に平手打ちする頭と尾があることを保証します。境界の前または後に配列を追加する場合、少なくとも.concat() !!!!を使用する必要があります。

注:スプレッドオペレーター_..._を使用すると、これをすべて簡単に実行できます。

1

別のスレッドで述べたように、上記の答えは非常に大きな配列(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]);
       }
    }
}
0
Gabriel Kohen

ここに特別なトリックのない私のバージョンがあります:

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;
}
0
arlomedia
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);
0
Bhesh Gurung

新しい配列を作成せずに配列に別の配列を挿入する場合、最も簡単な方法は、Pushまたはunshiftapplyとともに使用することです

例えば:

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の両方が可変個の引数を取るために機能します。おまけに、アレイを接続する端を簡単に選択できます!

0
RangerMauve