Scala vers le bas ou décroissant pour la boucle?

115

Dans Scala, vous utilisez souvent un itérateur pour faire une forboucle dans un ordre croissant comme:

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

Comment feriez-vous pour que ça passe de 10 à 1? Je suppose que 10 to 1donne un itérateur vide (comme les mathématiques de plage habituelles)?

J'ai fait un script Scala qui le résout en appelant reverse sur l'itérateur, mais ce n'est pas sympa à mon avis, est-ce que la suite est la voie à suivre?

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))
Félix
la source

Réponses:

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
la source
2
@Felix: De rien. J'aurais également dû souligner qu'il y a aussi untilque vous pouvez utiliser à la place de topour exclure le point final de droite de la plage. Le point de terminaison de gauche est toujours inclus.
Randall Schulz
Je connaissais déjà le till, le till est aussi une fonction sur les entiers, cependant, "by" doit être une fonction sur la plage / l'itérateur tout ce qui est retourné par les fonctions "to" et "until". Merci quand même :)
Felix
5
La réponse de Randall est la meilleure, mais je pense qu'elle Range.inclusive(10, 1, -1)mérite d'être mentionnée.
john sullivan
37

La réponse de @Randall est aussi bonne que l'or, mais par souci de finition, je voulais ajouter quelques variantes:

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
la source
9
+1 pour le premier, mais le second est mauvais - moins lisible que byet l'OMI ne doit en aucun cas être utilisé
om-nom-nom
4
Le deuxième est mal mais construit l'intuition sur ce qui est disponible
Zaheer
10

Scala fournit de nombreuses façons de travailler en boucle vers le bas.

1ère solution: avec "vers" et "par"

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

2ème solution: avec "vers" et "inverser"

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

3ème solution: avec "à" uniquement

//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
la source
6

Ayant programmé en Pascal, je trouve cette définition agréable à utiliser:

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
}

Utilisé de cette façon:

for (i <- 10 downto 0) println(i)
LP_
la source
Merci pour la réponse. J'ai du mal à utiliser cette solution. Voici mon stacktrace:Error:(57, 17) value class may not be a member of another class implicit class RichInt(val value: Int) extends AnyVal { ^
robert
Comme le suggère le message d'erreur (pas une trace de pile), vous ne pouvez pas définir la classe de valeur à l'intérieur d'une autre classe. Soit le définir en dehors de celui-ci, soit comme dans un objet, soit supprimer la extends AnyValpièce (ce qui ne sert qu'à supprimer une surcharge).
LP_
1

Vous pouvez utiliser la classe Range:

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

Vous pouvez utiliser : for (i <- 0 to 10 reverse) println(i)

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

La boucle s'exécutera jusqu'à la valeur == 0, décrémentée à chaque fois de -1.

n1cula
la source