Javascript - memasukkan array ke dalam array lain

91

Apa cara yang lebih efisien untuk memasukkan array ke dalam array lain.

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

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

Iterasi a2 menggunakan sambatan terlihat agak buruk dari sudut pandang kinerja jika array a2 besar.

Terima kasih.

ic3
sumber
2
itu bukan hanya satu item tetapi sebuah array, jadi sambungan tidak berfungsi
ic3

Jawaban:

182

Anda dapat menggunakan splicekombinasi dengan beberapa applytipuan:

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

Di ES2015 +, Anda dapat menggunakan operator penyebaran untuk membuatnya sedikit lebih bagus

a1.splice(2, 0, ...a2);
nickf
sumber
10
@icCube: Saya baru saja menjalankan tolok ukur, membandingkan metode ini dengan yang ada di jawaban patrick. Ini dimulai dengan a1 dan a2 seperti pada contoh, dan memasukkan variabel a2 ke a1 10.000 kali (sehingga pada akhirnya, Anda memiliki array dengan 20.005 elemen). Metode ini membutuhkan waktu: 81ms , metode slice + concat membutuhkan waktu 156ms (diuji di Chrome 13) . Tentu saja, ini disertai dengan peringatan standar bahwa dalam banyak kasus, keterbacaan akan lebih penting daripada kecepatan.
nickf
3
@nick: Di chrome jika array menampung lebih dari 130000 item applyakan memunculkan pengecualian stackoverflow. jsfiddle.net/DcHCY Juga terjadi di jsPerf Saya percaya pada FF dan IE ambang batasnya sekitar 500k
Tidak
mengapa Anda menggunakan apply sebagai kebalikan dari memanggil sambungan secara langsung dan meneruskan argumen?
Peter P.
@ FrançoisWahl, ini adalah masalah serius yang sering diabaikan orang dalam jawaban mereka. Saya telah mengambil contoh Anda dan membuatnya bekerja dengan utara elemen 1 juta: stackoverflow.com/a/41466395/1038326
Gabriel Kohen
Saya baru saja mencoba ini (Juni 2017) dan cara tercepat untuk ukuran array kecil dan ukuran array besar (di Chrome, FF, dan Edge) tampaknya adalah target.slice(0, insertIndex).concat(insertArr, target.slice(insertIndex)); jsperf.com/inserting-an-array-within-an-array
Alex Dima
14

Apakah itu salah pada awalnya. Seharusnya digunakan concat()sebagai gantinya.

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

Contoh: http://jsfiddle.net/f3cae/1/

Ekspresi ini menggunakan slice(0, 2)[docs] untuk mengembalikan dua elemen pertama a1(di mana 0indeks awal, dan 2elemen deleteCount, meskipun a1tidak diubah).

Hasil antara :[1,2]

Ini kemudian menggunakan concat(a2)[docs] untuk ditambahkan a2ke akhir [1,2].

Hasil tengah : [1,2,21,22].

Selanjutnya, a1.slice(2)dipanggil dalam sebuah jejak .concat()di ujung ekor ekspresi ini, yang berjumlah [1,2,21,22].concat(a1.slice(2)).

Panggilan ke slice(2), memiliki argumen bilangan bulat positif, akan mengembalikan semua elemen setelah elemen ke-2, dihitung dengan bilangan asli (seperti dalam, ada lima elemen, jadi [3,4,5]akan dikembalikan dari a1). Cara lain untuk mengatakan ini adalah bahwa argumen indeks integer tunggal memberi tahu a1.slice()di posisi mana dalam array untuk mulai mengembalikan elemen (indeks 2 adalah elemen ketiga).

Hasil antara :[1,2,21,22].concat([3,4,5])

Akhirnya, detik .concat()ditambahkan [3,4,5]ke akhir [1,2,21,22].

Hasil :[1,2,21,22,3,4,5]

Mungkin tergoda untuk mengubahnya Array.prototype, tetapi seseorang dapat dengan mudah memperluas objek Array menggunakan warisan prototypal dan menyuntikkan objek baru tersebut ke dalam proyek Anda.

Namun, bagi mereka yang hidup di pinggir ...

Contoh: 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 );
pengguna113716
sumber
Saya mendapatkan a1 dengan 6 item bukan 7 -> [1,2, [21,22], 3,4,5]
ic3
berhasil! terima kasih banyak, mari kita tunggu beberapa hari untuk tetapi ini sebagai jawaban terbaik ... aneh mereka tidak memiliki fungsi js untuk ini.
ic3
Saya lebih suka yang ini
Kimchi Man
Singkatnya, mesin JS harus mengembalikan empat larik sebelum ekspresi selesai. Saya suka logika solusinya, tetapi mungkin tidak optimal dalam hal pertimbangan ruang. Namun saya setuju bahwa ini bagus dan sangat kompatibel dengan lintas browser. Ada biaya untuk menggunakan operator penyebaran karena berfungsi pada koleksi, tetapi saya mungkin mengambil alih mengembalikan empat array dalam jangka panjang.
Anthony Rutledge
4

The spread Operator memungkinkan ekspresi diperluas di tempat-tempat di mana beberapa argumen (untuk panggilan fungsi) atau beberapa elemen (untuk literal array) diharapkan.

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

Hikmat Sijapati
sumber
3

Saya ingin menemukan cara untuk melakukan ini dengan splice()dan tanpa iterasi: 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];

Dalam bentuk fungsi tujuan umum:

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
}
jfriend00
sumber
Ini memodifikasi a2larik juga, yang mungkin sangat tidak diinginkan. Selain itu, Anda tidak perlu pergi ke Array.prototypesaat Anda memiliki fungsi slice di sana a1atau a2.
nickf
Saya sadar itu memodifikasi a2. OP dapat memutuskan apakah itu masalah atau tidak. Apakah ada yang salah dengan pergi ke prototipe untuk mendapatkan metodenya? Tampaknya lebih sesuai bagi saya karena saya hanya menginginkan metode dan objek ditambahkan ke apply()metode.
jfriend00
Tidak, itu fungsi yang persis sama, tetapi yang satu lebih pendek: Array.prototype.splicevs a1.splice:)
nickf
Menambahkan fungsi penyisipan array tujuan umum.
jfriend00
.concatmengembalikan array baru, itu tidak mengubah yang sudah ada seperti itu splice. Seharusnyaargs = args.concat(arrayToInsert);
nickf
3

Ada beberapa jawaban yang benar-benar kreatif untuk pertanyaan ini di sini. Berikut adalah solusi sederhana bagi mereka yang baru memulai dengan array. Ini dapat dibuat untuk bekerja sepenuhnya hingga ke browser yang mendukung ECMAScript 3, jika diinginkan.

Ketahui sesuatu tentang sambungan sebelum memulai.

Jaringan Pengembang Mozilla: Array.prototype.splice ()

Pertama, pahami dua bentuk penting dari .splice().

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

Metode 1) Hapus elemen x (deleteCount), mulai dari indeks yang diinginkan.

let startIndex = 0, 
    deleteCount = 2;

a1.splice(startIndex, deleteCount); // returns [1,2], a1 would be [3,4]

Metode 2) Hapus elemen setelah indeks awal yang diinginkan ke akhir array.

a1.splice(2); // returns [3,4], a1 would be [1,2]

Dengan menggunakan .splice(), tujuannya adalah untuk membagi a1menjadi array kepala dan ekor dengan menggunakan salah satu dari dua bentuk di atas.

Menggunakan metode # 1, nilai yang dikembalikan akan menjadi kepala, dan a1ekor.

let head = a1.splice(startIndex, deleteCount); // returns [1,2], a1 would be [3,4]

Sekarang, dalam satu gerakan, satukan kepala, badan ( a2), dan ekor

[].concat(head, a2, a1);

Dengan demikian, solusi ini lebih seperti dunia nyata daripada solusi lain yang disajikan sejauh ini. Bukankah ini yang akan Anda lakukan dengan Lego? ;-) Ini adalah fungsi, dilakukan dengan menggunakan metode # 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]

Singkat:

/**
*@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));
}

Lebih aman:

/**
*@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));
}

Keuntungan dari solusi ini meliputi:

1) Premis sederhana mendominasi solusi - isi larik kosong.

2) Tata nama kepala, badan, dan ekor terasa alami.

3) Tidak ada panggilan ganda ke .slice(). Tidak ada pemotongan sama sekali.

4) Tidak .apply(). Sangat tidak perlu.

5) Menghindari rangkaian metode.

6) Bekerja di ECMAScript 3 dan 5 hanya dengan menggunakan varalih-alih letatau const.

** 7) Memastikan bahwa akan ada kepala dan ekor untuk ditampar ke tubuh, tidak seperti banyak solusi lain yang disajikan. Jika Anda menambahkan larik sebelum, atau setelah, batas, Anda setidaknya harus menggunakan .concat()!!!!

Catatan: Penggunaan opearator penyebaran ...membuat semua ini lebih mudah dilakukan.

Anthony Rutledge
sumber
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);
Bhesh Gurung
sumber
0

Ini versi saya tanpa trik khusus:

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;
}
arlomedia
sumber
Dalam kasus ini, mungkin lebih mudah untuk hanya .reverse () array nilai_baru, daripada menambahkan insert_index untuk setiap iterasi. Tentu saja, ketika start_index adalah nol atau start_index - 1, efisiensi solusi ini buruk, dibandingkan dengan hanya menggunakan .concat () tanpa loop eksplisit, atau unshift () atau push () `dengan .apply().
Anthony Rutledge
0

Jika Anda ingin memasukkan array lain ke dalam array tanpa membuat yang baru, cara termudah adalah menggunakan salah satu pushatau unshiftdenganapply

Misalnya:

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

Ini berfungsi karena keduanya pushdan unshiftmengambil sejumlah variabel argumen. Bonus, Anda dapat dengan mudah memilih ujung mana untuk melampirkan array!

RangerMauve
sumber
Hanya dengan melakukan a1.concat(a2)atau a2.concat(a1)saya telah menemukan sesuatu yang lebih mudah dari apa yang Anda sarankan. Namun, masalahnya adalah memasukkan larik di antara batas larik, tidak secara eksklusif menambahkan larik ke awal atau akhir. ;-)
Anthony Rutledge
0

Seperti yang disebutkan di utas lain, jawaban di atas tidak akan berfungsi dalam larik yang sangat besar (200 ribu elemen). Lihat jawaban alternatif di sini yang melibatkan sambungan dan dorongan manual: 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]);
       }
    }
}
Gabriel Kohen
sumber