Scala: apa cara terbaik untuk menambahkan elemen ke Array?

111

Katakanlah saya punya Array[Int]suka

val array = Array( 1, 2, 3 )

Sekarang saya ingin menambahkan elemen ke array, katakan nilainya 4, seperti pada contoh berikut:

val array2 = array + 4     // will not compile

Saya tentu saja dapat menggunakan System.arraycopy()dan melakukan ini sendiri, tetapi harus ada fungsi pustaka Scala untuk ini, yang tidak dapat saya temukan. Terima kasih atas petunjuknya!

Catatan:

  1. Saya sadar bahwa saya dapat menambahkan Array elemen lain, seperti di baris berikut, tetapi itu tampak terlalu membulat:

    val array2b = array ++ Array( 4 )     // this works
  2. Saya menyadari kelebihan dan kekurangan List vs Array dan di sinilah saya karena berbagai alasan yang secara khusus tertarik untuk memperluas Array.

Edit 1

Terima kasih atas jawaban yang menunjuk ke :+metode operator. Inilah yang saya cari. Sayangnya, ini agak lebih lambat daripada implementasi metode append () khusus yang menggunakan arraycopy- sekitar dua hingga tiga kali lebih lambat. Melihat implementasinya SeqLike[], builder dibuat, lalu array ditambahkan ke dalamnya, lalu append dilakukan melalui builder, lalu builder dirender. Bukan implementasi yang baik untuk array. Saya melakukan patokan cepat dengan membandingkan kedua metode tersebut, melihat waktu tercepat dari sepuluh siklus. Melakukan 10 juta pengulangan item tunggal yang ditambahkan ke instance array 8-elemen dari beberapa kelas Foomembutuhkan waktu 3,1 detik dengan :+dan 1,7 detik dengan append()metode sederhana yang menggunakanSystem.arraycopy();melakukan 10 juta pengulangan item tunggal pada array 8 elemen Long membutuhkan waktu 2,1 detik dengan :+dan 0,78 detik dengan append()metode sederhana . Bertanya-tanya apakah ini tidak dapat diperbaiki di perpustakaan dengan penerapan khusus untuk Array?

Edit 2

Untuk apa nilainya, saya mengajukan tiket: https://issues.scala-lang.org/browse/SI-5017

Gregor Scheidt
sumber
11
Mengapa tidak digunakan ArrayBufferdan +=metodenya? Itu akan memberi Anda amortisasi O (1) tambahkan.
Fred Foo
1
Dalam skala, System.arraycopy(...)digantikan olehArray.copy(...)
paradigmatik
1
Anda sadar akan kelebihan dan kekurangan List vs Array, namun kaget dengan hasil benchmark 10 juta tambahan?
pengguna tidak diketahui
Dapatkah Anda menjalankan kembali benchmark Anda menggunakan ArrayBufferyang diubah setelah penambahan terakhir ke sebuah array (with toArray)?
paradigmatis
@paradigmatic: Tolok ukurnya tentu saja bukan 10 juta yang ditambahkan ke array yang sama, tetapi 10 juta pengulangan item tunggal yang ditambahkan ke array 8 elemen. Saya memperbarui pertanyaan sesuai.
Gregor Scheidt

Jawaban:

204

Anda dapat menggunakan :+untuk menambahkan elemen ke larik dan +:untuk menambahkannya:

0 +: array :+ 4

harus menghasilkan:

res3: Array[Int] = Array(0, 1, 2, 3, 4)

Ini sama dengan implementasi lainnya Seq.

tenshi
sumber
3
Ini sama untuk koleksi terurut skala lainnya , tidak bekerja dengan set misalnya (karena prepend dan append tidak berarti apa-apa untuk Set).
Nicolas
@Nicolas Urutan apa pun. Berurutan berarti diurutkan .
Daniel C. Sobral
@Daniel Ya, saya hanya memiliki lubang memori kecil ketika saya menulis komentar dan saya tidak menemukan kata "urutan" yang jelas
Nicolas
@ tenshi akankah semua operator ini membuat array baru? Ya, memang (dari: + kode)Array.copy(repr, 0, result, 0, repr.length)
Timofey
59
val array2 = array :+ 4
//Array(1, 2, 3, 4)

Bekerja juga "terbalik":

val array2 = 4 +: array
Array(4, 1, 2, 3)

Ada juga versi "di tempat":

var array = Array( 1, 2, 3 )
array +:= 4
//Array(4, 1, 2, 3)
array :+= 0
//Array(4, 1, 2, 3, 0)
Landei
sumber
11
Saya hanya ingin tahu mengapa koleksi Array tidak menggunakan metode append (), seperti ArrayBuffer. Menurut pendapat saya, ini lebih Koordinasi dan menyatukan daripada menggunakan operator baru: + / +:
Djvu
8

Mungkin yang termudah:

Array(1, 2, 3) :+ 4

Sebenarnya, Array secara implisit dapat diubah menjadi WrappedArray

Nicolas
sumber
Dalam hal ini, itu akan menjadi konversi prioritas lebih tinggi ke ArrayOps
Didier Dupont