配列項目を別の配列にコピーする


918

dataArray新しい配列にプッシュしたいJavaScript配列がありますnewArray。私はしたくない場合を除きnewArray[0]しますdataArray。すべてのアイテムを新しい配列にプッシュしたい:

var newArray = [];

newArray.pushValues(dataArray1);
newArray.pushValues(dataArray2);
// ...

またはさらに良い:

var newArray = new Array (
   dataArray1.values(),
   dataArray2.values(),
   // ... where values() (or something equivalent) would push the individual values into the array, rather than the array itself
);

したがって、新しい配列には、個々のデータ配列のすべての値が含まれています。pushValues利用可能な短縮形がいくつかあるのでdataArray、アイテムを1つずつ追加して、各個人を反復処理する必要はありませんか?


このURLを参照してください。stackoverflow.com
questions / 351409 / appending


回答:


1248

次のように、concat関数を使用します。

var arrayA = [1, 2];
var arrayB = [3, 4];
var newArray = arrayA.concat(arrayB);

newArrayとなり[1, 2, 3, 4]arrayA及びarrayB不変; concat結果のために新しい配列を作成し、返します)。



16
私は、実行力のある実行が非常に優れていることに同意します。しかしために、正確に、CONCATされていないことを目的に連結配列に?だから標準的なはずです。または、concatを使用して他に良いことはありますか?また、ブラウザのJSエンジンの実装が悪いためか、それをどこで使用している場合でも、遅くなる可能性がありますか?いつか直るかもしれません。ハック速度の最適化よりもコードの保守性を選択します。うーん....
ビターブルー

3
また、状況をベンチマークしました:concatとpush.applyです。Google Chrome:高速(concat =勝者)、: Opera高速(concat =勝者)、: IE遅い(concat =勝者)Firefox、:遅い(push.apply =勝者、ただしChromeの連結よりも10倍遅い)...悪いJSエンジンの実装について話す。
Bitterblue

15
どのようにされて連結する二つの配列方法については受け入れ答え押す別に1を!これらは2つの異なる操作です。
kaqqao 2017年

@kaqqao pushは、値の配列をフラット化しないためです。concat質問が必要とするものを達成します。
WiseGuyEh 2017年

644

配列が巨大でない場合(下記の警告を参照)、push()値を追加する配列のメソッドを使用できます。push()複数のパラメーターを取ることができるので、そのapply()メソッドを使用して、プッシュされる値の配列を関数パラメーターのリストとして渡すことができます。これには、concat()新しい配列を作成するのではなく、配列に要素を追加して配置するよりも利点があります。

ただし、大規模な配列(メンバー数が100,000以上)の場合、このトリックは失敗する可能性があります。このような配列の場合、ループを使用する方が適切です。詳細については、https://stackoverflow.com/a/17368101/96100を参照してください。

var newArray = [];
newArray.push.apply(newArray, dataArray1);
newArray.push.apply(newArray, dataArray2);

これを関数に一般化したい場合があります:

function pushArray(arr, arr2) {
    arr.push.apply(arr, arr2);
}

...またはをArrayプロトタイプに追加します。

Array.prototype.pushArray = function(arr) {
    this.push.apply(this, arr);
};

var newArray = [];
newArray.pushArray(dataArray1);
newArray.pushArray(dataArray2);

...または元のエミュレートpush()事実用いて複数のパラメータを可能にすることによって、方法concat()のような、push()複数のパラメータを可能にします。

Array.prototype.pushArray = function() {
    this.push.apply(this, this.concat.apply([], arguments));
};

var newArray = [];
newArray.pushArray(dataArray1, dataArray2);

これは最後の例のループベースのバージョンで、大きな配列とIE <= 8を含むすべての主要なブラウザーに適しています。

Array.prototype.pushArray = function() {
    var toPush = this.concat.apply([], arguments);
    for (var i = 0, len = toPush.length; i < len; ++i) {
        this.push(toPush[i]);
    }
};

9
注:newArray.push.apply(newArray, dataArray1);同じものを示しますArray.prototype.push.applay(newArray,dataArra1);

これは古いブラウザと互換性がありますか?
DamienÓCeallaigh


1
@DamienÓCeallaigh:はい。これは、IE 6以前のブラウザーと互換性があります。
Tim Down

これは貧弱なプログラミング慣行の縮図です。Array.prototype.concat悪いことではなく、単に誤解され、誤用されることもあります。これらの状況下では、誤解されているだけで誤用されていません。
ジャックギフィン2018

446

「将来に備えた」返信をもう1つ追加します

ECMAScript 6では、Spread構文を使用できます

let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1.push(...arr2);

console.log(arr1)

スプレッド構文は、すべての主要なブラウザにまだ含まれていません。現在の互換性については、この(継続的に更新される)互換性の表を参照してください。

ただし、Babel.jsではスプレッド構文を使用できます。

編集:

パフォーマンスに関するコメントについては、以下のJack Giffinの返信を参照してください。連結演算子はスプレッド演算子よりも優れており、高速であるようです。


7
TypeScriptを使用している場合は、spread演算子も使用できます。ES5をターゲットにすると、コンパイルしてになりますnewArray.apply(newArray, dataArray1)
AJリチャードソン

5
注:3番目の配列で結果が必要な場合(最初の質問で必要と思われたため、arr1を変更しない場合)、newArray = [... arr1、... arr2]
dim

ああ、それは知りませんでした。ありがとう。編集コメントを追加しました。
カレルビレク2018

そのときconcatがどのように機能するかと同様に、永続的である(元の配列を変更する)ボーナスがあります。
Rob

@robertmylneスプレッド演算子は明らかに元の配列を変更せず、代わりに、解析されたすべての配列の内容の新しいコピーを作成します。
ジャックギフィン2018年

145

MDNからエレガントな方法を見つけました

var vegetables = ['parsnip', 'potato'];
var moreVegs = ['celery', 'beetroot'];

// Merge the second array into the first one
// Equivalent to vegetables.push('celery', 'beetroot');
Array.prototype.push.apply(vegetables, moreVegs);

console.log(vegetables); // ['parsnip', 'potato', 'celery', 'beetroot']

またはspread operator、ES6 の機能を使用できます。

let fruits = [ 'apple', 'banana'];
const moreFruits = [ 'orange', 'plum' ];

fruits.push(...moreFruits); // ["apple", "banana", "orange", "plum"]

1
これは、質問が求めていたものではありません。問題は、古い配列を変更するのではなく、毎回新しい配列を作成する方法を求めることです。
ジャックギフィン2018


13

以下は私にとって最も簡単なようです:

var newArray = dataArray1.slice();
newArray.push.apply(newArray, dataArray2);

"push"は可変数の引数を取るためapplypush関数のメソッドを使用して、別の配列のすべての要素をプッシュできます。最初の引数(ここでは「newArray」)を「this」として使用し、配列の要素を残りの引数として使用して、pushの呼び出しを作成します。

slice最初のステートメントのinは最初の配列のコピーを取得するため、変更しないでください。

更新スライスが利用可能なバージョンのJavaScriptを使用している場合、push式を次のように簡略化できます。

newArray.push(...dataArray2)

1
MDNでは、「2つのアレイのマージ」の例としても言及されています
Wilt

12

以下の関数は配列の長さに問題がなく、提案されたすべてのソリューションよりもパフォーマンスが優れています。

function pushArray(list, other) {
    var len = other.length;
    var start = list.length;
    list.length = start + len;
    for (var i = 0; i < len; i++ , start++) {
        list[start] = other[i];
    }
}

残念ながら、jsprefは私の提出物を受け入れることを拒否しているため、ここに、benchmark.jsを使用した結果があります。

        Name            |   ops/sec   |  ± %  | runs sampled
for loop and push       |      177506 |  0.92 | 63
Push Apply              |      234280 |  0.77 | 66
spread operator         |      259725 |  0.40 | 67
set length and for loop |      284223 |  0.41 | 66

どこ

forループとプッシュは:

    for (var i = 0, l = source.length; i < l; i++) {
        target.push(source[i]);
    }

プッシュ適用:

target.push.apply(target, source);

スプレッドオペレーター:

    target.push(...source);

そして最後に、「セットの長さとforループ」は上記の関数です


この質問は、既存のアレイを変更するのではなく、毎回新しいアレイを作成する方法を探しています。
ジャックギフィン2018

10

𝗥𝗲𝘀𝗲𝗮𝗿𝗰𝗵𝗔𝗻𝗱𝗥𝗲𝘀𝘂𝗹𝘁𝘀

事実については、jsperfでパフォーマンステストを実行し、コンソールでいくつかのことを確認しています。調査にはウェブサイトirt.orgを使用しています。以下は、これらすべてのソースをまとめたものと、下部にある関数の例です。

╔═══════════════╦══════╦═════════════════╦════════ ═══════╦═════════╦══════════╗
║メソッド║Concat║slice&push.apply║push.apply x2║ForLoop║Spread║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║mOps /秒║179║104║76║81║28║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║スパース配列║はい!║Onlyスライス║║なしたぶん2   ║no║
║スパースを維持║║配列(1番目の引数)║║║║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║サポート║MSIE4║MSIE5.5║MSIE 5.5║MSIE 4║Edge12║
║(ソース)║NNav4║NNav4.06║NNav 4.06║NNav 3║ MSIE  NNav ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║配列のような行為║いいえ║プッシュされた║のみ║はい!║はい!have持っている場合║
アレイ║║array(第2引数)║║║iterator║like 1   ║
╚═══════════════╩══════╩═════════════════╩════════ ═══════╩═════════╩══════════╝
1配列のようなオブジェクトにSymbol.iteratorプロパティがない場合は、
  拡散すると例外がスローされます。
2コードによって異なります。次のコード例「YES」は、スパース性を維持します。
function mergeCopyTogether(inputOne, inputTwo){
   var oneLen = inputOne.length, twoLen = inputTwo.length;
   var newArr = [], newLen = newArr.length = oneLen + twoLen;
   for (var i=0, tmp=inputOne[0]; i !== oneLen; ++i) {
        tmp = inputOne[i];
        if (tmp !== undefined || inputOne.hasOwnProperty(i)) newArr[i] = tmp;
    }
    for (var two=0; i !== newLen; ++i, ++two) {
        tmp = inputTwo[two];
        if (tmp !== undefined || inputTwo.hasOwnProperty(two)) newArr[i] = tmp;
    }
    return newArr;
}

上で見たように、コンキャットはほとんどの場合、パフォーマンスとスペアアレイのスパース性を維持する機能の両方を実現する方法であると主張します。次に、配列のような(DOMNodeListsのようなdocument.body.children)場合は、forループを使用することをお勧めします。これは、2番目にパフォーマンスが高く、疎な配列を保持する他の唯一のメソッドだからです。以下では、混乱を解消するために、スパース配列と配列のようなものが何を意味するかを簡単に説明します。

𝗧𝗵𝗲𝗙𝘂𝘁𝘂𝗿𝗲

最初は、これはまぐれであり、ブラウザベンダは最終的にArray.prototype.pushを最適化して、Array.prototype.concatに勝る十分な速度になると考える人もいます。違う!Array.prototype.concatは、データを単純にコピーして貼り付けるだけなので、(少なくとも原則として)常に高速になります。以下は、32ビット配列の実装がどのように見えるかを示す簡略化された説得力のある視覚的な図です(実際の実装はLOTがより複雑であることに注意してください)。

バイト║ここにデータ
═════╬═══════════
0x00║int nonNumericPropertiesLength = 0x00000000
0x01║同上
0x02║同上
0x03║同上
0x00║intの長さ= 0x00000001
0x01║同上
0x02║同上
0x03║同上
0x00║int valueIndex = 0x00000000
0x01║同上
0x02║同上
0x03║同上
0x00║int valueType = JS_PRIMITIVE_NUMBER
0x01║同上
0x02║同上
0x03║同上
0x00║uintptr_t valuePointer = 0x38d9eb60(またはメモリ内の任意の場所)
0x01║同上
0x02║同上
0x03║同上

上記のように、そのようなものをコピーするために必要なことは、バイトごとにコピーするのとほとんど同じくらい簡単です。Array.prototype.push.applyを使用すると、データを単純にコピーして貼り付けるだけではありません。「.apply」は、配列内の各インデックスを確認し、それをArray.prototype.pushに渡す前に引数のセットに変換する必要があります。次に、Array.prototype.pushは毎回さらに多くのメモリを追加で割り当てる必要があり、(一部のブラウザ実装では)スパース性のために位置検索データを再計算することもできます。

それを考える別の方法はこれです。ソースアレイ1は、ホチキス止めされた紙の大きなスタックです。ソースアレイ2も、別の大きな紙のスタックです。あなたがする方が速くなりますか

  1. ストアに移動し、各ソースアレイのコピーに必要な十分な紙を購入します。次に、用紙の各ソースアレイスタックをコピー機に通して、2つのコピーを一緒にホチキス止めします。
  2. ストアに行って、最初のソースアレイの1つのコピーに十分な紙を購入します。次に、ソースアレイを新しい用紙に手動でコピーし、空白のまばらなスポットを確実に埋めます。次に、店に戻って、2番目のソースアレイ用に十分な紙を購入します。次に、2番目のソースアレイを通過し、コピーに空白のギャップがないことを確認しながらコピーします。次に、コピーしたすべての用紙を一緒にホチキス止めします。

上記の類推では、オプション#1はArray.prototype.concatを表し、オプション#2はArray.prototype.push.applyを表します。これを、類似のJSperfでテストしてみましょう。これは、ソリッド配列ではなく、スパース配列に対してメソッドをテストする点だけが異なります。ここで見つけることができます。

したがって、この特定のユースケースのパフォーマンスの将来はArray.prototype.pushではなく、Array.prototype.concatにあると私は主張します。

𝗖𝗹𝗮𝗿𝗶𝗳𝗶𝗰𝗮𝘁𝗶𝗼𝗻𝘀

𝗦𝗽𝗮𝗿𝗲𝗔𝗿𝗿𝗮𝘆𝘀

配列の特定のメンバーが単に見つからない場合。例えば:

// This is just as an example. In actual code, 
// do not mix different types like this.
var mySparseArray = [];
mySparseArray[0] = "foo";
mySparseArray[10] = undefined;
mySparseArray[11] = {};
mySparseArray[12] =  10;
mySparseArray[17] = "bar";
console.log("Length:   ", mySparseArray.length);
console.log("0 in it:  ", 0 in mySparseArray);
console.log("arr[0]:   ", mySparseArray[0]);
console.log("10 in it: ", 10 in mySparseArray);
console.log("arr[10]   ", mySparseArray[10]);
console.log("20 in it: ", 20 in mySparseArray);
console.log("arr[20]:  ", mySparseArray[20]);

または、JavaScriptを使用すると、スペア配列を簡単に初期化できます。

var mySparseArray = ["foo",,,,,,,,,,undefined,{},10,,,,,"bar"];

𝗔𝗿𝗿𝗮𝘆-𝗟𝗶𝗸𝗲𝘀

配列のようなものは、少なくともlengthプロパティを持つオブジェクトですが、new Arrayまたはで初期化されていません[]。たとえば、以下のオブジェクトは配列のように分類されます。

{0:「foo」、1:「バー」、長さ:2}
document.body.children
新しいUint8Array(3)
  • これは配列に似ています。これは、a(n)(型付き)配列ですが、配列に強制変換するとコンストラクターが変更されるためです。
(function(){戻り引数})()

配列のようなものをスライスのような配列に強制変換するメソッドを使用して何が起こるかを観察します。

  • 注:パフォーマンス上の理由から、関数の引数でスライスを呼び出すことはお勧めできません。

配列のようなものをconcatのような配列に強制しないメソッドを使用して何が起こるかを観察します。


9

JavaScript ES6では、配列を値に変換するスプレッド演算子として...演算子を使用できます。その後、次のようなことができます:

const myArray = [1,2,3,4,5];
const moreData = [6,7,8,9,10];

const newArray = [
  ...myArray,
  ...moreData,
];

構文は簡潔ですが、これが内部でどのように機能するか、および大規模な配列でのパフォーマンスへの影響はわかりません。


2
babelがどのように変換するかを見てみるArray.push.applyテクニックを使用するよりも遅くないはずです。
emil.c 2017

1
@JackGiffin Ryanが内部でどのように機能するか、パフォーマンスへの影響が何であるかを知らないとRyanが言ったことに言及しただけで、実際にはこのアプローチを提案していませんでした。いずれにせよ、あなたはあなたの答え、素晴らしい研究で非常に良い仕事をしました、そのような詳細を知ることは常に良いことです。
emil.c

9

これがES6の方法です

var newArray = [];
let dataArray1 = [1,2,3,4]
let dataArray2 = [5,6,7,8]
newArray = [...dataArray1, ...dataArray2]
console.log(newArray)

上記の方法は、ほとんどの場合に適していconcatますが、考慮に入れないケースもあります。たとえば、配列に数十万のアイテムがある場合などです。

    let dataArray1 = [1,2,3,4]
    let dataArray2 = [5,6,7,8]
    let newArray = dataArray1.concat(dataArray2);
    console.log(newArray)


8

Array.prototype.push.applyについての答えはたくさんあります。ここに明確な例があります:

var dataArray1 = [1, 2];
var dataArray2 = [3, 4, 5];
var newArray = [ ];
Array.prototype.push.apply(newArray, dataArray1); // newArray = [1, 2]
Array.prototype.push.apply(newArray, dataArray2); // newArray = [1, 2, 3, 4, 5]
console.log(JSON.stringify(newArray)); // Outputs: [1, 2, 3, 4, 5]

ES6構文がある場合:

var dataArray1 = [1, 2];
var dataArray2 = [3, 4, 5];
var newArray = [ ];
newArray.push(...dataArray1); // newArray = [1, 2]
newArray.push(...dataArray2); // newArray = [1, 2, 3, 4, 5]
console.log(JSON.stringify(newArray)); // Outputs: [1, 2, 3, 4, 5]


4

元の配列を変更する場合は、次の方法で展開してプッシュできます。

var source = [1, 2, 3];
var range = [5, 6, 7];
var length = source.push(...range);

console.log(source); // [ 1, 2, 3, 5, 6, 7 ]
console.log(length); // 6

同じ型の項目のみがsource配列に入るようにする場合(たとえば、数値と文字列を混在させない)、TypeScriptを使用します。

/**
 * Adds the items of the specified range array to the end of the source array.
 * Use this function to make sure only items of the same type go in the source array.
 */
function addRange<T>(source: T[], range: T[]) {
    source.push(...range);
}

2

2つの配列aとbがあります。ここで行ったコードは、配列aの値が配列bにプッシュされます。

let a = [2, 4, 6, 8, 9, 15]

function transform(a) {
    let b = ['4', '16', '64']
    a.forEach(function(e) {
        b.push(e.toString());
    });
    return b;
}

transform(a)

[ '4', '16', '64', '2', '4', '6', '8', '9', '15' ]

1
回答としてコードを投稿しないでください。コードの機能と問題の解決方法を説明してください。
Patrick Hund 2017年

0

これを試して:

var arrayA = [1, 2];
var arrayB = [3, 4];
var newArray = arrayB.reduce((pre, cur) => [...pre, ...cur], arrayA);
console.log(newArray)

-2

push()関数の代わりにIEのconcat関数を使用します。例、

var a=a.concat(a,new Array('amin'));

1
どちらもIEと非常に互換性があります
Jack Giffin

-3

これは動作するコードであり、正常に動作します。

var els = document.getElementsByTagName('input'), i;
var invnum = new Array();
var k = els.length;
for(i = 0; i < k; i++){invnum.push(new Array(els[i].id,els[i].value))}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.