Comment sortir une boucle?
var largest=0
for(i<-999 to 1 by -1) {
for (j<-i to 1 by -1) {
val product=i*j
if (largest>product)
// I want to break out here
else
if(product.toString.equals(product.toString.reverse))
largest=largest max product
}
}
Comment transformer des boucles imbriquées en récursivité de queue?
Extrait de Scala Talk au FOSDEM 2009 http://www.slideshare.net/Odersky/fosdem-2009-1013261 sur la 22e page:
Briser et continuer Scala n'en a pas. Pourquoi? Ils sont un peu impératifs; mieux utiliser de nombreuses fonctions plus petites Problème d'interaction avec les fermetures. Ils ne sont pas nécessaires!
Quelle est l'explication?
scala
for-loop
break
tail-recursion
TiansHUo
la source
la source
i
etj
. Si ce code s'exécute jusqu'à la fin sans sortir de la boucle, le résultat est,906609
mais en sortant tôt de la boucle, le résultat est90909
si la rupture de la boucle ne rend pas le code "plus efficace" car il modifie le résultat.Réponses:
Vous avez trois (ou plus) options pour sortir des boucles.
Supposons que vous souhaitiez additionner des nombres jusqu'à ce que le total soit supérieur à 1000. Vous essayez
sauf que vous voulez arrêter quand (somme> 1000).
Que faire? Il existe plusieurs options.
(1a) Utilisez une construction qui inclut un conditionnel que vous testez.
(avertissement - cela dépend des détails de la façon dont le test takeWhile et le foreach sont entrelacés pendant l'évaluation, et ne devraient probablement pas être utilisés dans la pratique!).
(1b) Utilisez la récursion de queue au lieu d'une boucle for, en profitant de la facilité d'écriture d'une nouvelle méthode dans Scala:
(1c) Revenez à l'utilisation d'une boucle while
(2) Jetez une exception.
(2a) Dans Scala 2.8+, ceci est déjà pré-packagé en
scala.util.control.Breaks
utilisant une syntaxe qui ressemble beaucoup à votre ancienne rupture familière de C / Java:(3) Mettez le code dans une méthode et utilisez return.
C'est intentionnellement rendu pas trop facile pour au moins trois raisons auxquelles je peux penser. Tout d'abord, dans les grands blocs de code, il est facile d'ignorer les instructions "continue" et "break", ou de penser que vous vous échappez de plus ou de moins que vous ne l'êtes réellement, ou d'avoir besoin de casser deux boucles que vous ne pouvez pas faire facilement de toute façon - donc l'utilisation standard, bien que pratique, a ses problèmes, et donc vous devriez essayer de structurer votre code d'une manière différente. Deuxièmement, Scala a toutes sortes d'imbrications que vous ne remarquerez probablement même pas, donc si vous pouviez vous échapper, vous seriez probablement surpris de la fin du flux de code (en particulier avec les fermetures). Troisièmement, la plupart des "boucles" de Scala ne sont pas en fait des boucles normales - ce sont des appels de méthode qui ont leur propre boucle,Looplike, il est difficile de trouver un moyen cohérent de savoir ce que la «rupture» et autres devraient faire. Donc, pour être cohérent, la chose la plus sage à faire est de ne pas avoir du tout de "pause".
Remarque : il existe des équivalents fonctionnels de tous ces éléments dans lesquels vous retournez la valeur de
sum
plutôt que de la muter en place. Ce sont des Scala plus idiomatiques. Cependant, la logique reste la même. (return
devientreturn x
, etc.).la source
breakable
section ... et tous ces cerceaux juste pour éviter le malbreak
, hmm ;-) Vous devez admettre que la vie est ironique.break
] Si cela ressemble à unbreak
et qu'il fonctionne comme unbreak
, en ce qui me concerne c'est unbreak
.Cela a changé dans Scala 2.8 qui a un mécanisme pour utiliser les pauses. Vous pouvez maintenant effectuer les opérations suivantes:
la source
Ce n'est jamais une bonne idée de sortir d'une boucle for. Si vous utilisez une boucle for, cela signifie que vous savez combien de fois vous souhaitez répéter. Utilisez une boucle while avec 2 conditions.
par exemple
la source
Pour ajouter Rex Kerr, répondez d'une autre manière:
(1c) Vous pouvez également utiliser un garde dans votre boucle:
la source
Puisqu'il n'y en a pas encore
break
dans Scala, vous pouvez essayer de résoudre ce problème en utilisant unereturn
déclaration. Par conséquent, vous devez mettre votre boucle intérieure dans une fonction, sinon le retour ignorerait la boucle entière.Scala 2.8 comprend cependant un moyen de briser
http://www.scala-lang.org/api/rc/scala/util/control/Breaks.html
la source
utilisez le module Break http://www.tutorialspoint.com/scala/scala_break_statement.htm
la source
Utilisez simplement une boucle while:
la source
Une approche qui génère les valeurs sur une plage au fur et à mesure que nous itérons, jusqu'à une condition de rupture, au lieu de générer d'abord une plage entière, puis d'itérer dessus, en utilisant
Iterator
, (inspiré de l'utilisation @RexKerr deStream
)la source
Voici une version récursive de queue. Comparé aux for-comprehensions, c'est un peu cryptique, certes, mais je dirais que c'est fonctionnel :)
Comme vous pouvez le voir, la fonction tr est la contrepartie des for-comprehensions externes et tr1 de la for-comprehensions interne. Vous êtes les bienvenus si vous connaissez un moyen d'optimiser ma version.
la source
La solution la plus proche serait la suivante:
La j-itération est faite sans nouvelle portée, et la génération du produit ainsi que la condition sont effectuées dans l'instruction for (pas une bonne expression - je n'en trouve pas de meilleure). La condition est inversée, ce qui est assez rapide pour cette taille de problème - peut-être que vous gagnez quelque chose avec une pause pour les boucles plus grandes.
String.reverse se convertit implicitement en RichString, c'est pourquoi je fais 2 revers supplémentaires. :) Une approche plus mathématique pourrait être plus élégante.
la source
Le
breakable
package tiers est une alternative possiblehttps://github.com/erikerlandson/breakable
Exemple de code:
la source
Méthode de base pour rompre la boucle, en utilisant la classe Breaks. En déclarant la boucle cassable.
la source
Tout simplement, nous pouvons faire en scala est
production :
la source
Ironiquement, l'effraction de Scala
scala.util.control.Breaks
est une exception:Le meilleur conseil est: NE PAS utiliser break, continue et goto! OMI, ce sont les mêmes, les mauvaises pratiques et une source perverse de toutes sortes de problèmes (et de discussions brûlantes) et finalement "considérées comme nuisibles". Le bloc de code est structuré, également dans cet exemple les ruptures sont superflues. Notre Edsger W. Dijkstra † a écrit:
la source
J'ai une situation comme le code ci-dessous
J'utilise une bibliothèque java et le mécanisme est que ctx.read lève une exception quand il ne trouve rien. J'étais coincé dans la situation suivante: je dois rompre la boucle lorsqu'une exception a été levée, mais scala.util.control.Breaks.break utilise Exception pour rompre la boucle, et il était dans le bloc catch donc il a été intercepté.
J'ai eu laide façon de résoudre ce problème: faites la boucle pour la première fois et obtenez le compte de la longueur réelle. et l'utiliser pour la deuxième boucle.
retirer une pause de Scala n'est pas si bon, quand vous utilisez des bibliothèques java.
la source
Je suis nouveau sur Scala, mais que diriez-vous pour éviter de lever des exceptions et de répéter les méthodes:
utilisez-le comme ceci:
si vous ne voulez pas casser:
la source
Une utilisation intelligente de la
find
méthode de collecte fera l'affaire pour vous.la source
la source
Je ne sais pas à quel point le style Scala a changé au cours des 9 dernières années, mais j'ai trouvé intéressant que la plupart des réponses existantes utilisent
vars
, ou difficile à lire la récursivité. La clé pour sortir tôt est d'utiliser une collection paresseuse pour générer vos candidats potentiels, puis vérifiez la condition séparément. Pour générer les produits:Ensuite, pour trouver le premier palindrome à partir de cette vue sans générer toutes les combinaisons:
Pour trouver le plus grand palindrome (bien que la paresse ne vous achète pas beaucoup car vous devez quand même consulter la liste entière):
Votre code d'origine vérifie en fait le premier palindrome qui est plus grand qu'un produit suivant, ce qui revient à vérifier le premier palindrome, sauf dans une condition aux limites étrange que je ne pense pas que vous vouliez. Les produits ne diminuent pas strictement de façon monotone. Par exemple,
998*998
est supérieur à999*997
, mais apparaît beaucoup plus tard dans les boucles.Quoi qu'il en soit, l'avantage de la génération paresseuse séparée et de la vérification de l'état est que vous l'écrivez à peu près comme s'il utilisait la liste entière, mais il ne génère que ce dont vous avez besoin. Vous obtenez en quelque sorte le meilleur des deux mondes.
la source