Scala ke bawah atau menurun untuk loop?

115

Di Scala, Anda sering menggunakan iterator untuk melakukan forperulangan dalam urutan yang meningkat seperti:

for(i <- 1 to 10){ code }

Bagaimana Anda melakukannya sehingga berubah dari 10 menjadi 1? Saya kira 10 to 1memberikan iterator kosong (seperti matematika kisaran biasa)?

Saya membuat skrip Scala yang menyelesaikannya dengan memanggil terbalik pada iterator, tetapi itu tidak baik menurut saya, apakah berikut ini cara yang harus dilakukan?

def nBeers(n:Int) = n match {

    case 0 => ("No more bottles of beer on the wall, no more bottles of beer." +
               "\nGo to the store and buy some more, " +
               "99 bottles of beer on the wall.\n")

    case _ => (n + " bottles of beer on the wall, " + n +
               " bottles of beer.\n" +
               "Take one down and pass it around, " +
              (if((n-1)==0)
                   "no more"
               else
                   (n-1)) +
                   " bottles of beer on the wall.\n")
}

for(b <- (0 to 99).reverse)
    println(nBeers(b))
Felix
sumber

Jawaban:

229
scala> 10 to 1 by -1
res1: scala.collection.immutable.Range = Range(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
Randall Schulz
sumber
2
@ Felix: Sama-sama. Saya juga harus menunjukkan bahwa ada juga untilyang dapat Anda gunakan sebagai pengganti tountuk mengecualikan titik akhir kanan dari jangkauan. Titik akhir sisi kiri selalu disertakan.
Randall Schulz
Saya sudah tahu tentang sampai, sampai juga merupakan fungsi pada bilangan bulat, namun, "oleh" harus menjadi fungsi pada rentang / iterator apa pun yang dikembalikan dari fungsi "ke" dan "sampai". Terima kasih :)
Felix
5
Jawaban Randall adalah yang terbaik, tapi menurut saya Range.inclusive(10, 1, -1)pantas disebutkan.
john sullivan
37

Jawaban dari @Randall bagus sekali, tapi demi penyelesaian saya ingin menambahkan beberapa variasi:

scala> for (i <- (1 to 10).reverse) {code} //Will count in reverse.

scala> for (i <- 10 to(1,-1)) {code} //Same as with "by", just uglier.
Chirlo
sumber
9
+1 untuk yang pertama, tapi yang kedua jahat - kurang terbaca bydan IMO tidak boleh digunakan dalam keadaan apa pun
om-nom-nom
4
Yang kedua jahat tetapi membangun intuisi atas apa yang tersedia
Zaheer
10

Scala menyediakan banyak cara untuk bekerja secara berurutan.

Solusi Pertama: dengan "to" dan "by"

//It will print 10 to 0. Here by -1 means it will decremented by -1.     
for(i <- 10 to 0 by -1){
    println(i)
}

Solusi Kedua: Dengan "ke" dan "mundur"

for(i <- (0 to 10).reverse){
    println(i)
}

Solusi ke-3: hanya dengan "ke"

//Here (0,-1) means the loop will execute till value 0 and decremented by -1.
for(i <- 10 to (0,-1)){
    println(i)
}
Dipak Shaw
sumber
6

Setelah diprogram dalam Pascal, saya merasa definisi ini bagus untuk digunakan:

implicit class RichInt(val value: Int) extends AnyVal {
  def downto (n: Int) = value to n by -1
  def downtil (n: Int) = value until n by -1
}

Digunakan dengan cara ini:

for (i <- 10 downto 0) println(i)
LP_
sumber
Terima kasih atas jawabannya. Saya mengalami masalah saat menggunakan solusi ini. Ini stacktrace saya:Error:(57, 17) value class may not be a member of another class implicit class RichInt(val value: Int) extends AnyVal { ^
robert
Seperti yang disarankan oleh pesan kesalahan (bukan pelacakan tumpukan), Anda tidak dapat menentukan kelas nilai di dalam kelas lain. Entah mendefinisikannya di luar itu, seperti di sebuah objek, atau menghapus extends AnyValbagiannya (yang hanya berfungsi untuk menghilangkan beberapa overhead).
LP_
1

Anda dapat menggunakan kelas Range:

val r1 = new Range(10, 0, -1)
for {
  i <- r1
} println(i)
KaaPex
sumber
1

Kamu bisa memakai : for (i <- 0 to 10 reverse) println(i)

Jonny
sumber
0
for (i <- 10 to (0,-1))

Perulangan akan dijalankan hingga nilai == 0, setiap kali dikurangi -1.

n1cula
sumber