Saya tidak tahu apakah ada cara yang tepat untuk mendapatkan ukuran daftar dalam skala, tetapi untuk situasi Anda, Anda dapat menggunakan urutan.
Qusay Fantazia
Apakah pertanyaan ini masih belum terjawab? Meminta karena Anda mungkin lupa menerimanya.
Tobias Kolb
Jawaban:
150
Versi yang lebih bersih dari salah satu jawaban lainnya adalah:
val s =Seq("apple","oranges","apple","banana","apple","oranges","oranges")
s.groupBy(identity).mapValues(_.size)
memberi Mapdengan hitungan untuk setiap item dalam urutan aslinya:
Map(banana ->1, oranges ->3, apple ->3)
Pertanyaannya menanyakan bagaimana menemukan hitungan item tertentu. Dengan pendekatan ini, solusi akan membutuhkan pemetaan elemen yang diinginkan ke nilai hitungannya sebagai berikut:
Itu adalah fungsi identitas, seperti yang didiskusikan di sini . Fungsi tersebut groupBymembutuhkan fungsi yang diterapkan pada elemen sehingga mengetahui cara mengelompokkannya. Sebuah alternatif untuk mengelompokkan string dalam jawaban berdasarkan identitas mereka bisa jadi, katakanlah, pengelompokan berdasarkan panjangnya ( groupBy(_.size)) atau dengan huruf pertama ( groupBy(_.head)).
ohruunuruus
2
Kekurangannya adalah banyak koleksi yang tidak berguna (karena hanya ukuran yang dibutuhkan) yang dibuat.
Yann Moisan
bagaimana jika saya ingin mendefinisikan peta akumulator dalam ekspresi itu daripada membuat peta baru?
Tobias Kolb
128
koleksi scala memang memiliki count:list.count(_ == 2)
Versi yang lebih bersih adalahs.groupBy(identity).mapValues(_.size)
ohruunuruus
1
@ohruunuruus ini seharusnya menjadi jawaban (vs komentar); saya akan senang untuk antusias upvote, jika itu (dan pilih sebagai jawaban terbaik jika saya adalah OP);
doug
1
@doug agak baru untuk SO dan tidak yakin, tapi senang menurut
ohruunuruus
27
list.groupBy(i=>i).mapValues(_.size)
memberi
Map[Int,Int]=Map(1->1,2->3,7->1,3->1,4->3)
Perhatikan bahwa Anda dapat mengganti (i=>i)dengan identityfungsi bawaan:
val list =List(1,2,4,2,4,7,3,2,4)// Using the provided count method this would yield the occurrences of each value in the list:
l map(x => l.count(_ == x))List[Int]=List(1,3,3,3,3,1,1,3,3)// This will yield a list of pairs where the first number is the number from the original list and the second number represents how often the first number occurs in the list:
l map(x =>(x, l.count(_ == x)))// outputs => List[(Int, Int)] = List((1,1), (2,3), (4,3), (2,3), (4,3), (7,1), (3,1), (2,3), (4,3))
Bagus, inilah yang saya cari, saya merasa sedih bahwa bahkan aliran Java (yang tidak bagus dalam beberapa aspek) memungkinkan ini dalam satu kali lintasan sementara Scala tidak bisa.
Dici
9
Saya mengalami masalah yang sama tetapi ingin menghitung beberapa item sekaligus ..
val s =Seq("apple","oranges","apple","banana","apple","oranges","oranges")
s.foldLeft(Map.empty[String,Int]){(m, x)=> m +((x, m.getOrElse(x,0)+1))}
res1: scala.collection.immutable.Map[String,Int]=Map(apple ->3, oranges ->3, banana ->1)
Saya agak curiga dengan benchmark ini karena tidak jelas ukuran datanya. The groupBysolusi melakukan toLowertapi yang lain tidak. Juga mengapa menggunakan pola yang cocok untuk peta - gunakan saja mapValues. Jadi gabungkan itu dan Anda mendapatkan def woGrouped(w: Word): Map[Char, Int] = w.groupBy(identity).mapValues(_.size)- mencobanya dan periksa kinerja untuk berbagai daftar ukuran. Akhirnya di solusi lain, mengapa a) mendeklarasikan mapdan b) menjadikannya var ?? Lakukan sajaw.foldLeft(Map.empty[Char, Int])...
samthebest
1
Terima kasih telah memberikan lebih banyak data (mengubah pilihan saya :). Saya pikir alasan mengapa implementasi groupBy menggunakan peta yang bisa berubah Builderyang dioptimalkan untuk peningkatan berulang. Ini kemudian mengubah peta yang bisa berubah menjadi yang tidak bisa diubah menggunakan MapBuilder. Mungkin ada beberapa evaluasi malas yang terjadi di bawah tenda juga untuk membuat segalanya lebih cepat.
Samthebest
@samthebest Anda cukup mencari penghitung dan menaikkannya. Saya tidak melihat apa yang bisa disimpan di cache di sana. Cache harus berupa peta dengan jenis yang sama.
Val
Saya tidak mengatakan itu menyimpan apa pun. Saya membayangkan peningkatan kinerja berasal dari penggunaan Builders, dan mungkin beberapa evaluasi malas.
samthebest
@samthebest lazy evaluation = evaluasi tertunda (dipanggil menurut nama) + caching. Anda tidak dapat berbicara tentang evaluasi malas tetapi tidak menyimpan cache.
Val
4
Saya tidak mendapatkan ukuran daftar yang digunakan lengthmelainkan sizeseperti yang disarankan oleh jawaban di atas karena masalah yang dilaporkan di sini .
val list =List("apple","oranges","apple","banana","apple","oranges","oranges")
list.groupBy(x=>x).map(t =>(t._1, t._2.size))
Wow, 4 iterasi melalui urutan aslinya! Bahkan seq.groupBy(identity).mapValues(_.size)hanya melalui dua kali.
WeaponsGrade
Jumlah iterasi mungkin tidak peduli untuk string kecil seperti "Alphabet", tetapi ketika berhadapan dengan jutaan item dalam koleksi, iterasi tentu melakukan hal!
WeaponsGrade
2
Coba ini, harus berhasil.
val list =List(1,2,4,2,4,7,3,2,4)
list.count(_==2)
Bagaimana ini berbeda dari jawaban xiefei yang diberikan tujuh tahun lalu?
jwvh
0
Berikut ini cara yang cukup mudah untuk melakukannya.
val data =List("it","was","the","best","of","times","it","was","the","worst","of","times")
data.foldLeft(Map[String,Int]().withDefaultValue(0)){case(acc, letter)=>
acc +(letter ->(1+ acc(letter)))}// => Map(worst -> 1, best -> 1, it -> 2, was -> 2, times -> 2, of -> 2, the -> 2)
Jawaban:
Versi yang lebih bersih dari salah satu jawaban lainnya adalah:
memberi
Map
dengan hitungan untuk setiap item dalam urutan aslinya:Pertanyaannya menanyakan bagaimana menemukan hitungan item tertentu. Dengan pendekatan ini, solusi akan membutuhkan pemetaan elemen yang diinginkan ke nilai hitungannya sebagai berikut:
sumber
groupBy
membutuhkan fungsi yang diterapkan pada elemen sehingga mengetahui cara mengelompokkannya. Sebuah alternatif untuk mengelompokkan string dalam jawaban berdasarkan identitas mereka bisa jadi, katakanlah, pengelompokan berdasarkan panjangnya (groupBy(_.size)
) atau dengan huruf pertama (groupBy(_.head)
).koleksi scala memang memiliki
count
:list.count(_ == 2)
sumber
Saya memiliki masalah yang sama dengan Sharath Prabhal, dan saya mendapatkan solusi lain (bagi saya yang lebih jelas):
Dengan hasil:
sumber
s.groupBy(identity).mapValues(_.size)
memberi
Perhatikan bahwa Anda dapat mengganti
(i=>i)
denganidentity
fungsi bawaan:sumber
sumber
Memulai
Scala 2.13
, metode groupMapReduce melakukannya sekaligus melalui daftar:Ini:
group
s daftar elemen (bagian grup dari grup MapReduce)map
s setiap kejadian nilai yang dikelompokkan ke 1 (bagian peta dari Map Reduce)reduce
nilai s dalam grup nilai (_ + _
) dengan menjumlahkannya (kurangi bagian dari groupMap Reduce ).Ini adalah versi sekali jalan dari apa yang dapat diterjemahkan oleh:
sumber
Saya mengalami masalah yang sama tetapi ingin menghitung beberapa item sekaligus ..
https://gist.github.com/sharathprabhal/6890475
sumber
Stream
dan jawaban yang diterima akan menghasilkan tujuan Anda "sekali jalan" ditambah kode yang lebih jelas.Jika Anda ingin menggunakannya seperti
list.count(2)
Anda harus mengimplementasikannya menggunakan Kelas Implisit .sumber
Jawaban singkat:
Jawaban panjang:
Menggunakan Scalaz , diberikan.
lalu semua ini (dalam urutan dari yang kurang disederhanakan menjadi lebih disederhanakan)
menghasilkan
sumber
Menarik untuk dicatat bahwa peta dengan nilai default 0, sengaja dirancang untuk kasus ini menunjukkan kinerja terburuk (dan tidak sesingkat
groupBy
)menghasilkan
Sangat mengherankan bahwa paling ringkas
groupBy
lebih cepat daripada peta yang bisa berubah!sumber
groupBy
solusi melakukantoLower
tapi yang lain tidak. Juga mengapa menggunakan pola yang cocok untuk peta - gunakan sajamapValues
. Jadi gabungkan itu dan Anda mendapatkandef woGrouped(w: Word): Map[Char, Int] = w.groupBy(identity).mapValues(_.size)
- mencobanya dan periksa kinerja untuk berbagai daftar ukuran. Akhirnya di solusi lain, mengapa a) mendeklarasikanmap
dan b) menjadikannya var ?? Lakukan sajaw.foldLeft(Map.empty[Char, Int])...
Builder
yang dioptimalkan untuk peningkatan berulang. Ini kemudian mengubah peta yang bisa berubah menjadi yang tidak bisa diubah menggunakanMapBuilder
. Mungkin ada beberapa evaluasi malas yang terjadi di bawah tenda juga untuk membuat segalanya lebih cepat.Builder
s, dan mungkin beberapa evaluasi malas.Saya tidak mendapatkan ukuran daftar yang digunakan
length
melainkansize
seperti yang disarankan oleh jawaban di atas karena masalah yang dilaporkan di sini .sumber
Ini opsi lain:
sumber
sumber
menggunakan kucing
sumber
seq.groupBy(identity).mapValues(_.size)
hanya melalui dua kali.Coba ini, harus berhasil.
Ini akan mengembalikan 3
sumber
Berikut ini cara yang cukup mudah untuk melakukannya.
sumber