Tampaknya Vector
sudah terlambat ke pesta koleksi Scala, dan semua posting blog berpengaruh sudah pergi.
Di Jawa ArrayList
adalah koleksi default - saya mungkin menggunakan LinkedList
tetapi hanya ketika saya sudah memikirkan algoritma dan cukup peduli untuk mengoptimalkan. Dalam Scala saya harus menggunakan Vector
sebagai default saya Seq
, atau mencoba bekerja ketika List
sebenarnya lebih tepat?
scala
vector
scala-collections
Duncan McGregor
sumber
sumber
List<String> l = new ArrayList<String>()
blog Scala akan membuat Anda percaya bahwa semua orang menggunakan Daftar untuk mendapatkan kebaikan koleksi persisten - tetapi apakah Vector bertujuan umum cukup bahwa kita harus menggunakannya di tempat Daftar?List
ketika saya mengetikSeq()
di REPL.IndexedSeq
.Seq
adalah lebih dari tiga tahun. Pada Scala 2.11.4 (dan sebelumnya), tipe konkret defaultSeq
adalahList
.Jawaban:
Sebagai aturan umum, standar untuk menggunakan
Vector
. Ini lebih cepat daripadaList
untuk hampir semua hal dan lebih hemat memori untuk urutan berukuran lebih dari sepele. Lihat dokumentasi kinerja relatif Vector ini dibandingkan dengan koleksi lainnya. Ada beberapa kelemahan untuk dilakukanVector
. Secara khusus:List
(meskipun tidak sebanyak yang Anda kira)Kelemahan lain sebelum Scala 2.10 adalah bahwa dukungan pencocokan pola lebih baik untuk
List
, tetapi ini diperbaiki pada 2.10 dengan generalisasi+:
dan:+
ekstraktor.Ada juga cara aljabar yang lebih abstrak untuk mendekati pertanyaan ini: urutan seperti apa yang secara konseptual Anda miliki? Juga, apa yang Anda lakukan secara konseptual dengannya? Jika saya melihat fungsi yang mengembalikan
Option[A]
, saya tahu fungsi itu memiliki beberapa lubang di domainnya (dan karenanya sebagian). Kita bisa menerapkan logika yang sama ini ke koleksi.Jika saya memiliki urutan tipe
List[A]
, saya secara efektif menegaskan dua hal. Pertama, algoritma saya (dan data) sepenuhnya terstruktur-tumpukan. Kedua, saya menegaskan bahwa satu-satunya hal yang akan saya lakukan dengan koleksi ini adalah penuh, O (n) traversal. Keduanya benar-benar berjalan seiring. Sebaliknya, jika saya memiliki sesuatu jenisVector[A]
, satu - satunya hal yang saya tegaskan adalah bahwa data saya memiliki urutan yang jelas dan panjang yang terbatas. Dengan demikian, pernyataan lebih lemahVector
, dan ini mengarah pada fleksibilitas yang lebih besar.sumber
case head +: tail
ataucase tail :+ head
. Untuk mencocokkan dengan kosong, Anda dapat melakukancase Seq()
dan sebagainya. Semua yang Anda butuhkan ada di API, yang lebih fleksibel daripadaList
'sList
diimplementasikan dengan daftar yang terhubung sendiri.Vector
diimplementasikan sesuatu seperti JavaArrayList
.Yah, a
List
bisa sangat cepat jika algoritme hanya dapat diimplementasikan dengan::
,head
dantail
. Saya mendapat pelajaran objek tentang hal itu baru-baru ini, ketika saya mengalahkan Javasplit
dengan menghasilkanList
bukanArray
, dan tidak bisa mengalahkan itu dengan hal lain.Namun,
List
memiliki masalah mendasar: tidak bekerja dengan algoritma paralel. Saya tidak dapat membagiList
menjadi beberapa segmen, atau menggabungkannya kembali, secara efisien.Ada beberapa koleksi lain yang dapat menangani paralelisme dengan lebih baik - dan
Vector
merupakan salah satunya.Vector
juga memiliki lokalitas besar - yangList
tidak - yang dapat menjadi nilai tambah nyata untuk beberapa algoritma.Jadi, semua hal dipertimbangkan,
Vector
adalah pilihan terbaik kecuali jika Anda memiliki pertimbangan khusus yang membuat salah satu koleksi lain lebih disukai - misalnya, Anda dapat memilihStream
jika Anda ingin evaluasi dan caching yang malas (Iterator
lebih cepat tetapi tidak menembolok), atauList
jika Algoritma secara alami diimplementasikan dengan operasi yang saya sebutkan.Ngomong-ngomong, lebih baik menggunakan
Seq
atauIndexedSeq
kecuali Anda menginginkan bagian tertentu dari API (sepertiList
itu::
), atau bahkanGenSeq
atauGenIndexedSeq
jika algoritma Anda dapat dijalankan secara paralel.sumber
Vector
adalah struktur data yang tidak berubah di Scala?Beberapa pernyataan di sini membingungkan atau bahkan salah, terutama gagasan yang tidak dapat diubah. Vektor di Scala mirip dengan ArrayList. Daftar dan Vektor keduanya tidak berubah, persisten (yaitu "murah untuk mendapatkan salinan yang dimodifikasi") struktur data. Tidak ada pilihan default yang masuk akal karena mereka mungkin untuk struktur data yang bisa berubah, tetapi lebih tergantung pada apa yang dilakukan algoritma Anda. Daftar adalah daftar yang ditautkan secara tunggal, sementara Vector adalah trie integer basis-32, yaitu jenis pohon pencarian dengan node derajat 32. Dengan menggunakan struktur ini, Vector dapat menyediakan operasi yang paling umum dengan cukup cepat, yaitu dalam O (log_32 ( n)). Itu berfungsi untuk prepend, append, update, akses acak, dekomposisi di head / tail. Iterasi dalam urutan berurutan adalah linear. Daftar di sisi lain hanya menyediakan iterasi linier dan waktu yang konstan, dekomposisi di kepala / ekor.
Ini mungkin terlihat seolah-olah Vector adalah pengganti yang baik untuk Daftar di hampir semua kasus, tetapi tergantung, dekomposisi dan iterasi sering merupakan operasi penting pada urutan dalam program fungsional, dan konstanta dari operasi ini (jauh) lebih tinggi untuk vektor karena untuk struktur yang lebih rumit. Saya membuat beberapa pengukuran, jadi iterasi sekitar dua kali lebih cepat untuk daftar, prepend sekitar 100 kali lebih cepat pada daftar, dekomposisi di kepala / ekor sekitar 10 kali lebih cepat pada daftar dan generasi dari yang dapat dilalui sekitar 2 kali lebih cepat untuk vektor. (Ini mungkin, karena Vector dapat mengalokasikan array 32 elemen sekaligus ketika Anda membangunnya menggunakan builder alih-alih menambahkan atau menambahkan elemen satu per satu).
Jadi struktur data mana yang harus kita gunakan? Pada dasarnya, ada empat kasus umum:
sumber
Untuk koleksi yang tidak berubah, jika Anda menginginkan urutan, keputusan utama Anda adalah apakah akan menggunakan a
IndexedSeq
atau aLinearSeq
, yang memberikan jaminan kinerja yang berbeda. IndexedSeq menyediakan akses acak cepat elemen dan operasi panjang cepat. LinearSeq menyediakan akses cepat hanya ke elemen pertama viahead
, tetapi juga memilikitail
operasi cepat . (Diambil dari dokumentasi Seq.)Untuk
IndexedSeq
Anda biasanya akan memilih aVector
.Range
danWrappedString
s juga IndexedSeqs.Untuk
LinearSeq
Anda biasanya akan memilihList
atau setara dengan malasStream
. Contoh lain adalahQueue
s danStack
s.Jadi dalam istilah Jawa,
ArrayList
digunakan mirip dengan ScalaVector
, danLinkedList
mirip dengan ScalaList
. Tetapi dalam Scala saya cenderung menggunakan Daftar lebih sering daripada Vektor, karena Scala memiliki dukungan yang jauh lebih baik untuk fungsi-fungsi yang mencakup melintasi urutan, seperti pemetaan, lipat, iterasi dll. Anda akan cenderung menggunakan fungsi-fungsi ini untuk memanipulasi daftar sebagai keseluruhan, daripada mengakses elemen individual secara acak.sumber
Vector
's iterasi adalah lebih cepat, tapi seseorang kebutuhan untuk patokan itu untuk memastikan.Vector
fisik ada bersama-sama di RAM dalam kelompok 32, yang lebih sepenuhnya sesuai dalam cache CPU ... jadi ada lebih sedikit cache missDalam situasi yang melibatkan banyak akses acak dan mutasi acak, a
Vector
(atau - seperti kata dokumen - aSeq
) tampaknya merupakan kompromi yang baik. Ini juga yang disarankan karakteristik kinerja .Juga,
Vector
kelas tampaknya bermain dengan baik di lingkungan terdistribusi tanpa banyak duplikasi data karena tidak perlu melakukan copy-on-write untuk objek lengkap. (Lihat: http://akka.io/docs/akka/1.1.3/scala/stm.html#persistent-datastructures )sumber
IndexedSeq
. Yang jugaVector
, tapi itu masalah lain.IndexedSeq
yang mengimplementasikanSeq
.Seq(1, 2, 3)
adalahLinearSeq
yang diimplementasikan menggunakanList
.Jika Anda sedang pemrograman dan membutuhkan akses acak, Seq adalah cara untuk pergi (kecuali Anda menginginkan Set, yang sering Anda lakukan). Kalau tidak, Daftar berfungsi dengan baik, kecuali operasinya tidak dapat diparalelkan.
Jika Anda tidak memerlukan struktur data yang tidak dapat diubah, tetap menggunakan ArrayBuffer karena itu adalah Scala yang setara dengan ArrayList.
sumber