Salin item array ke array lain

918

Saya memiliki array JavaScript dataArrayyang ingin saya dorong ke array baru newArray. Kecuali Aku tidak ingin newArray[0]menjadi dataArray. Saya ingin memasukkan semua item ke dalam array baru:

var newArray = [];

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

atau bahkan lebih baik:

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

Jadi sekarang array baru berisi semua nilai array data individual. Apakah ada singkatan seperti yang pushValuestersedia sehingga saya tidak perlu mengulangi setiap individu dataArray, menambahkan item satu per satu?

bba
sumber
Ini harus menjadi jawaban davidwalsh.name/combining-js-arrays
starikovs
Apakah ini menjawab pertanyaan Anda? Cara menggabungkan dua array dalam JavaScript dan menghapus duplikat item
HackerMan

Jawaban:

1249

Gunakan fungsi concat , seperti:

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

Nilai newArrayakan [1, 2, 3, 4]( arrayAdan arrayBtetap tidak berubah; concatmembuat dan mengembalikan array baru untuk hasilnya).

WiseGuyEh
sumber
16
Saya setuju bahwa eksekusi pemain sangat bagus. TAPI tidak concat persis untuk yang bertujuan untuk concat ke array? Jadi harus standar . Atau ada hal lain yang lebih baik untuk dilakukan dengan konser? Dan mungkin lambat hanya karena implementasi yang buruk dari mesin JS browser atau di mana pun Anda menggunakannya? Mungkin diperbaiki suatu hari. Saya akan memilih perawatan kode daripada optimasi kecepatan hacky. Hmm ....
Bitterblue
3
Juga saya hanya membandingkan situasinya: concat vs push.apply. Google Chrome: fast (concat = winner) ,: Operafast (concat = winner) ,: IEslow (concat = winner) Firefox,: slow (push.apply = winner, namun 10 kali lebih lambat dari concat Chrome) ... berbicara tentang implementasi mesin JS yang buruk .
Bitterblue
15
Bagaimana menggabungkan dua array jawaban yang diterima untuk bagaimana mendorong satu ke yang lain? Itu adalah dua operasi yang berbeda.
kaqqao
@kaqqao karena pushtidak akan meratakan array nilai. concatmencapai apa yang dituntut dari pertanyaan itu.
WiseGuyEh
644

Asalkan array Anda tidak besar (lihat peringatan di bawah), Anda dapat menggunakan push()metode array yang ingin Anda tambahkan nilai. push()dapat mengambil beberapa parameter sehingga Anda dapat menggunakan apply()metodenya untuk meneruskan array nilai yang akan didorong sebagai daftar parameter fungsi. Ini memiliki keunggulan dibandingkan menggunakan concat()menambahkan elemen ke array di tempat daripada membuat array baru.

Namun, tampaknya untuk array besar (dari urutan 100.000 anggota atau lebih), trik ini bisa gagal . Untuk array seperti itu, menggunakan loop adalah pendekatan yang lebih baik. Lihat https://stackoverflow.com/a/17368101/96100 untuk detailnya.

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

Anda mungkin ingin menggeneralisasi ini menjadi fungsi:

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

... atau tambahkan ke Arrayprototipe:

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

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

... atau meniru push()metode asli dengan memungkinkan beberapa parameter menggunakan fakta yang concat(), seperti push(), memungkinkan beberapa parameter:

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

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

Berikut ini adalah versi berbasis loop dari contoh terakhir, cocok untuk array besar dan semua browser utama, termasuk 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]);
    }
};
Tim Down
sumber
9
catatan: newArray.push.apply(newArray, dataArray1);memberikan hal yang sama sepertiArray.prototype.push.applay(newArray,dataArra1);
Apakah ini kompatibel dengan browser yang lebih lama?
Damien Ó Ceallaigh
1
@ DamienÓCeallaigh: Ya. Ini semua kompatibel dengan browser yang kembali ke IE 6 dan bahkan lebih awal.
Tim Down
Ini adalah contoh praktik pemrograman yang buruk. Array.prototype.concattidak buruk, melainkan hanya disalahpahami dan kadang-kadang disalahgunakan. Dalam keadaan ini, itu hanya disalahpahami, tetapi tidak disalahgunakan.
Jack Giffin
446

Saya akan menambahkan satu lagi "bukti masa depan"

Di ECMAScript 6, Anda dapat menggunakan sintaks Spread :

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

console.log(arr1)

Sintaksis yang menyebar belum termasuk dalam semua browser utama. Untuk kompatibilitas saat ini, lihat tabel kompatibilitas (terus diperbarui) ini .

Namun, Anda dapat menggunakan sintaks spread dengan Babel.js .

edit:

Lihat balasan Jack Giffin di bawah ini untuk komentar lebih lanjut tentang kinerja. Tampaknya concat masih lebih baik dan lebih cepat daripada operator yang tersebar.

Karel Bílek
sumber
7
Anda juga dapat menggunakan operator spread jika Anda menggunakan TypeScript. Jika Anda menargetkan ES5, itu akan dikompilasi ke newArray.apply(newArray, dataArray1).
AJ Richardson
5
Catatan: jika Anda membutuhkan hasil dalam array ketiga (sehingga tidak mengubah arr1, seperti pertanyaan awal tampaknya memerlukan), Anda dapat melakukan newArray = [... arr1, ... arr2]
redup
Oh, aku tidak tahu itu. Terima kasih. Saya telah menambahkan komentar edit.
Karel Bílek
Mirip dengan bagaimana concat akan berfungsi saat itu, dengan bonus menjadi gigih (bermutasi array asli).
Rob
@robertmylne Operator spread jelas tidak mengubah array asli, melainkan membuat salinan baru dari semua isi array yang dihapus.
Jack Giffin
145

Menemukan cara yang elegan dari 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']

Atau Anda dapat menggunakan spread operatorfitur ES6:

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

fruits.push(...moreFruits); // ["apple", "banana", "orange", "plum"]
Believe2014
sumber
1
Bukan itu pertanyaannya. Pertanyaannya adalah meminta cara untuk membuat array baru setiap kali, bukan memodifikasi array lama.
Jack Giffin
13
var a=new Array('a','b','c');
var b=new Array('d','e','f');
var d=new Array('x','y','z');
var c=a.concat(b,d)

Apakah itu menyelesaikan masalah Anda?

Sébastien VINCENT
sumber
13

Berikut ini tampaknya paling sederhana bagi saya:

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

Saat "push" mengambil sejumlah variabel argumen, Anda bisa menggunakan applymetode pushfungsi untuk mendorong semua elemen dari array lain. Itu membangun panggilan untuk mendorong menggunakan argumen pertama ("newArray" di sini) sebagai "ini" dan elemen-elemen dari array sebagai argumen yang tersisa.

Dalam slicepernyataan pertama mendapat salinan array pertama, jadi Anda tidak memodifikasinya.

Perbarui Jika Anda menggunakan versi javascript dengan slice yang tersedia, Anda dapat menyederhanakan pushekspresi menjadi:

newArray.push(...dataArray2)
shaunc
sumber
1
Disebutkan di sini di MDN sebagai contoh untuk "Menggabungkan dua array"
Wilt
12

Fungsi di bawah ini tidak memiliki masalah dengan panjang array dan berkinerja lebih baik daripada semua solusi yang disarankan:

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

Sayangnya, jspref menolak untuk menerima kiriman saya, jadi inilah hasilnya menggunakan 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

dimana

untuk loop dan push adalah:

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

Dorong Terapkan:

target.push.apply(target, source);

operator penyebaran:

    target.push(...source);

dan akhirnya 'atur panjang dan untuk loop' adalah fungsi di atas

Panos Theof
sumber
Pertanyaan ini mencari cara untuk membuat array baru setiap kali, bukan memodifikasi array yang ada.
Jack Giffin
10

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

Faktanya, tes kinerja di jsperf dan memeriksa beberapa hal di konsol dilakukan. Untuk penelitian, situs web irt.org digunakan. Di bawah ini adalah kumpulan dari semua sumber ini disatukan ditambah fungsi contoh di bagian bawah.

╔═══════════════╦══════╦═════════════════╦════════ ═══════╦═════════╦══════════╗
║ Metode ║Concat║slice & push.apply ║ push.apply x2 ║ ForLoop ║Sebarluaskan ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ mOps / Sec ║179 ║104 ║ 76 ║ 81 ║28 ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ Jarang array ║YES! ║Hanya diiris ║ tidak ║ Mungkin 2   ║tidak ║
║ jarang disimpan ║ ║array (argumen 1) ║ ║ ║ ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ Dukungan ║MSIE 4║MSIE 5.5 ║ MSIE 5.5 ║ MSIE 4 ║Edge 12 ║
║ ( sumber ) ║NNav 4║NNav 4,06 ║ NNav 4,06 ║ NNav 3 ║ MSIE  NNav ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║Array-like act║no ║Hanya yang didorong ║ YA! ║ YA! ║Jika punya ║
║like array ║ ║array (2 arg) ║ ║ ║iterator 1   ║
╚═══════════════╩══════╩═════════════════╩════════ ═══════╩═════════╩══════════╝
1 Jika objek mirip array tidak memiliki properti Symbol.iterator , maka cobalah
  untuk menyebarkannya akan melempar pengecualian.
2 Tergantung pada kode. Contoh kode berikut "YA" menjaga jarangnya.
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;
}

Seperti yang terlihat di atas, saya berpendapat bahwa Concat hampir selalu merupakan cara yang baik untuk kinerja dan kemampuan untuk mempertahankan jarangnya array cadangan. Kemudian, untuk array-like (seperti DOMNodeLists like document.body.children), saya akan merekomendasikan menggunakan for loop karena keduanya adalah yang paling berkinerja 2 dan satu-satunya metode lain yang mempertahankan array jarang. Di bawah ini, kita akan dengan cepat membahas apa yang dimaksud dengan array jarang dan array-suka untuk menghilangkan kebingungan.

𝗧𝗵𝗲 𝗙𝘂𝘁𝘂𝗿𝗲

Pada awalnya, beberapa orang mungkin berpikir bahwa ini adalah kebetulan dan bahwa vendor browser pada akhirnya akan mengoptimalkan Array.prototype.push agar cukup cepat untuk mengalahkan Array.prototype.concat. SALAH! Array.prototype.concat akan selalu lebih cepat (setidaknya pada prinsipnya) karena ini adalah copy-n-paste sederhana atas data. Di bawah ini adalah diagram persuado-visual yang disederhanakan dari apa yang terlihat seperti implementasi array 32-bit (harap dicatat implementasi nyata BANYAK yang lebih rumit)

Byte ║ Data di sini
═════╬═══════════
0x00 ║ int nonNumericPropertiesLength = 0x00000000
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ panjang int = 0x00000001
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ nilai intIndex = 0x00000000
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ int valueType = JS_PRIMITIVE_NUMBER
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid
0x00 ║ uintptr_t valuePointer = 0x38d9eb60 (atau di mana pun itu ada dalam memori)
0x01 ║ ibid
0x02 ║ ibid
0x03 ║ ibid

Seperti yang terlihat di atas, semua yang perlu Anda lakukan untuk menyalin sesuatu seperti itu hampir sesederhana menyalinnya byte demi byte. Dengan Array.prototype.push.apply, ini lebih dari sekadar copy-n-paste ke data. ".Apply" harus memeriksa setiap indeks dalam array dan mengubahnya menjadi seperangkat argumen sebelum meneruskannya ke Array.prototype.push. Kemudian, Array.prototype.push juga harus mengalokasikan lebih banyak memori setiap kali, dan (untuk beberapa implementasi browser) bahkan mungkin menghitung ulang beberapa data pencarian posisi untuk sparseness.

Cara alternatif untuk memikirkannya adalah ini. Sumber array satu adalah tumpukan besar kertas dijepit bersama. Array sumber dua juga merupakan tumpukan kertas lain. Apakah akan lebih cepat bagimu untuk melakukannya

  1. Pergi ke toko, beli cukup kertas yang dibutuhkan untuk salinan setiap larik sumber. Kemudian letakkan masing-masing tumpukan larik sumber kertas melalui mesin fotokopi dan menjilid dua salinan yang dihasilkan.
  2. Pergi ke toko, beli kertas secukupnya untuk satu salinan dari array sumber pertama. Kemudian, salin array sumber ke kertas baru dengan tangan, memastikan untuk mengisi setiap titik kosong yang kosong. Kemudian, kembali ke toko, beli kertas yang cukup untuk array sumber kedua. Kemudian, buka array sumber kedua dan salin sambil memastikan tidak ada celah kosong di salinan. Kemudian, pokok semua kertas yang disalin bersama.

Dalam analogi di atas, opsi # 1 mewakili Array.prototype.concat sedangkan # 2 mewakili Array.prototype.push.apply. Mari kita menguji ini dengan JSperf serupa yang hanya berbeda dalam hal ini menguji metode over array jarang, bukan solid array. Orang dapat menemukannya di sini .

Oleh karena itu, saya menyatakan kasus saya bahwa masa depan kinerja untuk kasus penggunaan khusus ini tidak terletak pada Array.prototype.push, melainkan pada Array.prototype.concat.

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

𝗦𝗽𝗮𝗿𝗲 𝗔𝗿𝗿𝗮𝘆𝘀

Ketika beberapa anggota array hilang. Sebagai contoh:

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

Atau, javascript memungkinkan Anda untuk menginisialisasi array cadangan dengan mudah.

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

𝗔𝗿𝗿𝗮𝘆-𝗟𝗶𝗸𝗲𝘀

Seperti array adalah objek yang memiliki setidaknya lengthproperti, tetapi tidak diinisialisasi dengan new Arrayatau []; Sebagai contoh, objek di bawah ini diklasifikasikan sebagai array-like.

{0: "foo", 1: "bar", panjang: 2}
document.body.children
Uint8Array baru (3)
  • Ini seperti array karena walaupun array (n) (diketik), memaksa ke array mengubah konstruktor.
(function () {return argumen}) ()

Amati apa yang terjadi menggunakan metode yang memaksa-suka array ke dalam array seperti slice.

  • CATATAN: Adalah praktik yang buruk untuk memanggil slice pada argumen fungsi karena kinerja.

Amati apa yang terjadi dengan menggunakan metode yang tidak memaksa array-like ke dalam array seperti concat.

Jack Giffin
sumber
9

Dengan JavaScript ES6, Anda dapat menggunakan ... operator sebagai operator spread yang pada dasarnya akan mengubah array menjadi nilai. Kemudian, Anda dapat melakukan sesuatu seperti ini:

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

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

Meskipun sintaksnya singkat, saya tidak tahu bagaimana ini bekerja secara internal dan apa implikasi kinerja pada array yang besar.

Ryan H.
sumber
2
Jika Anda melihat bagaimana babel mengubahnya , Anda akan melihat bahwa itu seharusnya tidak lebih lambat daripada menggunakan Array.push.applyteknik.
emil.c
1
@ JackGiffin Saya hanya merujuk pada apa yang Ryan katakan bahwa dia tidak tahu cara kerjanya secara internal dan apa implikasi kinerja, saya sebenarnya tidak menyarankan pendekatan ini. Bagaimanapun, Anda telah melakukan pekerjaan yang sangat baik pada jawaban Anda, riset yang bagus, selalu baik untuk mengetahui perincian seperti itu.
emil.c
9

Inilah cara ES6

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

Metode di atas baik untuk sebagian besar kasus dan kasus-kasus itu tidak perlu dipertimbangkan concat, seperti Anda memiliki ratusan ribu item dalam array.

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

Mamba hitam
sumber
8

Ada sejumlah jawaban yang berbicara tentang Array.prototype.push.apply . Ini adalah contoh yang jelas:

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]

Jika Anda memiliki sintaks 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]

Stephen Quan
sumber
4

Jika Anda ingin memodifikasi array asli, Anda dapat menyebar dan menekan:

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

Jika Anda ingin memastikan hanya item dengan tipe yang sama masuk dalam sourcearray (tidak mencampur angka dan string misalnya), maka gunakan 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);
}
orad
sumber
2

Kami memiliki dua array a dan b. kode yang dilakukan di sini adalah array nilai didorong ke array 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' ]
KARTHIKEYAN.A
sumber
1
Tolong jangan hanya mengirim kode sebagai jawaban. Jelaskan apa yang dilakukan kode dan bagaimana cara memecahkan masalah.
Patrick Hund
0

Coba ini:

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

alih-alih fungsi push () gunakan fungsi concat untuk IE. contoh,

var a=a.concat(a,new Array('amin'));
pengguna1911703
sumber
1
keduanya sangat kompatibel dengan IE
Jack Giffin
-3

Тhis adalah kode yang berfungsi dan berfungsi dengan baik:

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))}
pengguna4354031
sumber