web-dev-qa-db-ja.com

新しい配列を作成せずに、既存のJavaScript配列を別の配列で拡張する方法

既存の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)メソッドがあることを知っています、しかしそれは単に最初のものを拡張する代わりに新しい配列を作成します。 abよりもかなり大きい場合(つまりaをコピーしないもの)に効率的に機能するアルゴリズムが欲しいのですが。

注:これはの重複ではありません 配列に何かを追加する方法? - ここでの目的は、ある配列の内容全体を別の配列に追加し、それを「その場で」実行することです。

833
DzinX

.Push メソッドは複数の引数を取ることができます。 spread演算子 を使用して、2番目の配列のすべての要素を.Pushの引数として渡すことができます。

>>> a.Push(...b)

ご使用のブラウザがECMAScript 6をサポートしていない場合は、代わりに .apply を使用できます。

>>> a.Push.apply(a, b)

あるいは、もっと明確だと思うなら、

>>> Array.prototype.Push.apply(a,b)

配列bが長すぎると(ブラウザによっては約100,000要素からトラブルが発生します)、これらすべての解決策はスタックオーバーフローエラーで失敗します。 bが十分に短いことを保証できない場合は、他の回答で説明されている標準のループベースの手法を使用する必要があります。

1248
DzinX

更新2018 もっと良い答えは私の新しいものa.Push(...b)です。質問に実際に回答したことはないので、もうこれを支持しないでください。


単に「JavaScript array extend」を検索してここに来た人には、Array.concatを非常にうまく使用できます。

var a = [1, 2, 3];
a = a.concat([5, 4, 3]);

スレッドスターターが望んでいなかったように、Concatは新しい配列のコピーを返します。しかし、あなたは気にしないかもしれません(確かにほとんどの種類の使用のためにこれはうまくいくでしょう)。


これには、スプレッド演算子の形で、いくつかのNice ECMAScript 6シュガーもあります。

const a = [1, 2, 3];
const b = [...a, 5, 4, 3];

(コピーもします)

233

あなたはループベースのテクニックを使うべきです。このページの他の.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);

DzinXの回答 (Push.applyを使用)およびその他の.applyベースのメソッドは、追加している配列が大きいと失敗します(テストでは、私の場合、約150,000エントリがFirefoxで、> 500,000エントリがFirefoxです)。このエラーは this jsperf で発生しています。

2番目の引数として大きな配列を指定して 'Function.prototype.apply'が呼び出されると、呼び出しスタックサイズを超えたためにエラーが発生します。 (MDNは Function.prototype.applyを使用して呼び出しスタックサイズを超える危険性についてのメモを持っています - 「適用と組み込み関数」というタイトルのセクションを見てください。)

このページの他の答えとの速度比較のために、 this jsperf をチェックしてください(EaterOfCodeに感謝します)。ループベースの実装はArray.Push.applyを使うのと速度が似ていますが、Array.slice.applyより少し遅い傾向があります。

興味深いことに、追加している配列がスパースである場合、上記のforEachベースのメソッドは、sparsityを利用して.applyベースのメソッドより優れている可能性があります。 this jsperf 自分でテストしたい場合は/ /.

ところで、forEachの実装をさらに短くして次のように誘惑しないでください。

Array.prototype.extend = function (array) {
    array.forEach(this.Push, this);
}

これはゴミの結果を生み出すからです!どうして? Array.prototype.forEachは、それが呼び出す関数に3つの引数を提供するため、これらは(element_value、element_index、source_array)です。 "forEach(this.Push、this)"を使用すると、これらすべてがforEachの繰り返しごとに最初の配列にプッシュされます。

187
jcdude

私は最近最もエレガントな気がします:

arr1.Push(...arr2);

スプレッド演算子に関する MDNの記事 は、ES2015(ES6)でのこの素晴らしい提案方法について言及しています。

より良いプッシュ

例:プッシュは、既存のアレイの最後にアレイをプッシュするためによく使用されます。 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);

Jcdudeの答えのように、コールスタックがオーバーフローするので、arr2はそれほど大きくすることはできません(約100 000項目以下にする)。

144

JavaScriptでapply()を使用する理由を理解するのに役立ついくつかの単語:

apply()メソッドは、与えられたthis値と、配列として与えられた引数で関数を呼び出します。

Pushは list の項目が配列に追加されることを期待しています。ただし、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]; 

現時点では、すべてのブラウザでより短くより良いが完全にはサポートされていません。

また、 move を配列bからaに移動し、その過程でbを空にする場合は、次のようにします。

while(b.length) {
  a.Push(b.shift());
} 

結果は次のようになります。

a = [1, 2, 3, 4, 5, 6, 7];
b = [];
46
Alireza

JQueryを使いたいのであれば、 $ .merge() があります。

例:

a = [1, 2];
b = [3, 4, 5];
$.merge(a,b);

結果:a = [1, 2, 3, 4, 5]

38
Jules Colle

私は上記のa.Push.apply(a, b)メソッドが好きです、そしてあなたが望むならあなたはいつでもこのようなライブラリ関数を作成することができます:

Array.prototype.append = function(array)
{
    this.Push.apply(this, array)
}

そしてこのように使う

a = [1,2]
b = [3,4]

a.append(b)
19

splice()を使ってそれをすることは可能です:

b.unshift(b.length)
b.unshift(a.length)
Array.prototype.splice.apply(a,b) 
b.shift() // Restore b
b.shift() // 

しかし、それが醜いにもかかわらず、少なくともFirefox 3.0ではPush.applyより速くはありません。

13
Rafał Dowgird

この解決策は私にとってはうまくいきます(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);
4

下記のように拡張用のポリフィルを作成できます。それは配列に追加されます。他のメソッドをチェーニングできるように、インプレースで自分自身を返します。

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;
}
2
Mr. Polywhirl

私は非常にいい答えを見ることができます、そしてそれはすべてあなたのアレイサイズ、あなたの必要条件と目的によります。それはさまざまな方法で行うことができます。

JavaScriptにループを使用することをお勧めします。

var a = [1, 2];
var b = [3, 4, 5];

for (i = 0; i < b.length; i++) {
    a.Push(b[i]);
}

console.log(a)の出力は

Array [ 1, 2, 3, 4, 5 ]

それからあなたはあなた自身の機能を作ることができます:

function extendArray(a, b){
    for (i = 0; i < b.length; i++) {
        a.Push(b[i]);
    }
    return a;
}

console.log(extendArray(a, b));の出力は

Array [ 1, 2, 3, 4, 5 ]

150,000レコードを超える場合は、Array.extendの代わりにArray.Pushを使用してください。

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;
  };
}
0
Mahdi Pedram

答えを組み合わせています...

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]);
        };
    }  
}
0
zCoder

3つ以上の配列をマージするもう1つの解決策

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]

0
user3126309