¿Cómo puedo salir de un bucle en Scala?
for-loop break (17)
Aquí hay una versión recursiva de cola. En comparación con las previsiones, es un poco críptico, es cierto, pero diría que es funcional :)
def run(start:Int) = {
@tailrec
def tr(i:Int, largest:Int):Int = tr1(i, i, largest) match {
case x if i > 1 => tr(i-1, x)
case _ => largest
}
@tailrec
def tr1(i:Int,j:Int, largest:Int):Int = i*j match {
case x if x < largest || j < 2 => largest
case x if x.toString.equals(x.toString.reverse) => tr1(i, j-1, x)
case _ => tr1(i, j-1, largest)
}
tr(start, 0)
}
Como puede ver, la función tr es la contraparte de las comprensiones externas y tr1 de la interna. De nada si conoces una forma de optimizar mi versión.
¿Cómo puedo romper un bucle?
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
}
}
¿Cómo vuelvo anidado para bucles en recursión de cola?
De Scala Talk en FOSDEM 2009 http://www.slideshare.net/Odersky/fosdem-2009-1013261 en la página 22:
Romper y continuar, Scala no los tiene. ¿Por qué? Son un poco imperativos; Utilice mejor muchas funciones más pequeñas. Emita cómo interactuar con los cierres. ¡No son necesarios!
¿Cuál es la explicación?
Cerca de tu solución estaría esta:
var largest = 0
for (i <- 999 to 1 by -1;
j <- i to 1 by -1;
product = i * j;
if (largest <= product && product.toString.reverse.equals (product.toString.reverse.reverse)))
largest = product
println (largest)
La iteración j se realiza sin un nuevo alcance, y tanto la generación de producto como la condición se realizan en la declaración for (no es una buena expresión, no encuentro una mejor). La condición se invierte, lo cual es bastante rápido para el tamaño de ese problema; tal vez gane algo con un descanso para bucles más grandes.
String.reverse se convierte implícitamente a RichString, por lo que hago 2 reversos adicionales. :) Un enfoque más matemático podría ser más elegante.
Como aún no hay una break
en Scala, puede intentar resolver este problema utilizando una return
devolución. Por lo tanto, debe poner su bucle interno en una función, de lo contrario, el retorno omitirá todo el bucle.
Scala 2.8 sin embargo incluye una forma de romper
http://www.scala-lang.org/api/rc/scala/util/control/Breaks.html
El paquete breakable
terceros es una alternativa posible
https://github.com/erikerlandson/breakable
Código de ejemplo:
scala> import com.manyangled.breakable._
import com.manyangled.breakable._
scala> val bkb2 = for {
| (x, xLab) <- Stream.from(0).breakable // create breakable sequence with a method
| (y, yLab) <- breakable(Stream.from(0)) // create with a function
| if (x % 2 == 1) continue(xLab) // continue to next in outer "x" loop
| if (y % 2 == 0) continue(yLab) // continue to next in inner "y" loop
| if (x > 10) break(xLab) // break the outer "x" loop
| if (y > x) break(yLab) // break the inner "y" loop
| } yield (x, y)
bkb2: com.manyangled.breakable.Breakable[(Int, Int)] = com.manyangled.breakable.Breakable@34dc53d2
scala> bkb2.toVector
res0: Vector[(Int, Int)] = Vector((2,1), (4,1), (4,3), (6,1), (6,3), (6,5), (8,1), (8,3), (8,5), (8,7), (10,1), (10,3), (10,5), (10,7), (10,9))
Esto ha cambiado en Scala 2.8, que tiene un mecanismo para usar cortes. Ahora puedes hacer lo siguiente:
import scala.util.control.Breaks._
var largest = 0
// pass a function to the breakable method
breakable {
for (i<-999 to 1 by -1; j <- i to 1 by -1) {
val product = i * j
if (largest > product) {
break // BREAK!!
}
else if (product.toString.equals(product.toString.reverse)) {
largest = largest max product
}
}
}
Irónicamente, la ruptura de Scala en scala.util.control.Breaks
es una excepción:
def break(): Nothing = { throw breakException }
El mejor consejo es: NO use break, continue y goto! En mi opinión, son la misma práctica, una mala práctica y una fuente perversa de todo tipo de problemas (y discusiones candentes) y, finalmente, "considerados perjudiciales". Código de bloques estructurado, también en este ejemplo los cortes son superfluos. Nuestro Edsger W. Dijkstra † escribió:
La calidad de los programadores es una función decreciente de la densidad de las declaraciones de los programas que producen.
Nunca es una buena idea salir de un bucle for. Si está utilizando un bucle for, significa que sabe cuántas veces desea iterar. Utilice un bucle while con 2 condiciones.
por ejemplo
var done = false
while (i <= length && !done) {
if (sum > 1000) {
done = true
}
}
Para agregar Rex Kerr responda de otra manera:
(1c) También puedes usar un protector en tu bucle:
var sum = 0 for (i <- 0 to 1000 ; if sum<1000) sum += i
Simplemente lo podemos hacer en scala es
scala> import util.control.Breaks._
scala> object TestBreak{
def main(args : Array[String]){
breakable {
for (i <- 1 to 10){
println(i)
if (i == 5){
break;
} } } } }
salida:
scala> TestBreak.main(Array())
1
2
3
4
5
Solo usa un bucle while:
var (i, sum) = (0, 0)
while (sum < 1000) {
sum += i
i += 1
}
Soy nuevo en Scala, pero ¿qué hay de esto para evitar lanzar excepciones y repetir los métodos?
object awhile {
def apply(condition: () => Boolean, action: () => breakwhen): Unit = {
while (condition()) {
action() match {
case breakwhen(true) => return ;
case _ => { };
}
}
}
case class breakwhen(break:Boolean);
utilízalo así:
var i = 0
awhile(() => i < 20, () => {
i = i + 1
breakwhen(i == 5)
});
println(i)
si no quieres romper
awhile(() => i < 20, () => {
i = i + 1
breakwhen(false)
});
Tengo una situación como el siguiente código
for(id<-0 to 99) {
try {
var symbol = ctx.read("$.stocks[" + id + "].symbol").toString
var name = ctx.read("$.stocks[" + id + "].name").toString
stocklist(symbol) = name
}catch {
case ex: com.jayway.jsonpath.PathNotFoundException=>{break}
}
}
Estoy usando un java lib y el mecanismo es que ctx.read lanza una excepción cuando no puede encontrar nada. Me quedé atrapado en la situación de que: tengo que romper el bucle cuando se lanzó una Excepción, pero scala.util.control.Breaks.break usando Exception para romper el bucle, y estaba en el bloque catch por lo que fue capturado.
Tengo una manera fea de resolver esto: hacer el bucle por primera vez y obtener el recuento de la longitud real. y usarlo para el segundo bucle.
sacar un descanso de Scala no es tan bueno, cuando está utilizando algunas librerías java.
Tienes tres (o así) opciones para salir de los bucles.
Supongamos que desea sumar números hasta que el total sea mayor que 1000. Intenta
var sum = 0
for (i <- 0 to 1000) sum += i
excepto que desea detener cuando (suma> 1000).
¿Qué hacer? Hay varias opciones.
(1a) Use alguna construcción que incluya un condicional que pruebe.
var sum = 0
(0 to 1000).iterator.takeWhile(_ => sum < 1000).foreach(i => sum+=i)
(advertencia: esto depende de los detalles de cómo se intercalan la prueba de takeWhile y foreach durante la evaluación, y probablemente no se deben usar en la práctica).
(1b) Use la recursión de cola en lugar de un bucle for, aprovechando lo fácil que es escribir un nuevo método en Scala:
var sum = 0
def addTo(i: Int, max: Int) {
sum += i; if (sum < max) addTo(i+1,max)
}
addTo(0,1000)
(1c) Recurre al uso de un bucle while
var sum = 0
var i = 0
while (i <= 1000 && sum <= 1000) { sum += 1; i += 1 }
(2) Lanzar una excepción.
object AllDone extends Exception { }
var sum = 0
try {
for (i <- 0 to 1000) { sum += i; if (sum>=1000) throw AllDone }
} catch {
case AllDone =>
}
(2a) En Scala 2.8+, esto ya está preempaquetado en scala.util.control.Breaks
usando una sintaxis que se parece mucho a su viejo y familiar descanso de C / Java:
import scala.util.control.Breaks._
var sum = 0
breakable { for (i <- 0 to 1000) {
sum += i
if (sum >= 1000) break
} }
(3) Poner el código en un método y usar la devolución.
var sum = 0
def findSum { for (i <- 0 to 1000) { sum += i; if (sum>=1000) return } }
findSum
Esto se hace intencionalmente no demasiado fácil por al menos tres razones que se me ocurren. Primero, en bloques de código grandes, es fácil pasar por alto las declaraciones de "continuar" y "romper", o pensar que estás rompiendo más o menos de lo que realmente eres, o tener que romper dos bucles que no puedes hacer De todos modos, es fácil, por lo que el uso estándar, aunque práctico, tiene sus problemas, por lo que debe intentar estructurar su código de una manera diferente. En segundo lugar, Scala tiene todo tipo de anidaciones que probablemente ni notará, por lo que si pudiera salir de las cosas, probablemente se sorprenda de dónde terminó el flujo de código (especialmente con cierres). En tercer lugar, la mayoría de los "bucles" de Scala no son en realidad bucles normales, son llamadas de método que tienen su propio bucle, o son una recursión que puede o no ser un bucle, y aunque actúan en forma de bucle, es difícil para llegar a una manera consistente de saber qué "descanso" y cosas similares deberían hacer. Por lo tanto, para ser coherente, lo más inteligente es no tener una "ruptura" en absoluto.
Nota : hay equivalentes funcionales de todos estos en los que devuelve el valor de sum
lugar de mutarlo en su lugar. Estos son Scala más idiomáticos. Sin embargo, la lógica sigue siendo la misma. (el return
vuelve return x
, etc.).
Un enfoque que genera los valores en un rango a medida que iteramos, hasta una condición de ruptura, en lugar de generar primero un rango completo y luego iterar sobre él, usando Iterator
, (inspirado en el uso de Stream
en @RexKerr)
var sum = 0
for ( i <- Iterator.from(1).takeWhile( _ => sum < 1000) ) sum += i
El uso inteligente del método de find
de recolección hará el truco por ti.
var largest = 0
lazy val ij =
for (i <- 999 to 1 by -1; j <- i to 1 by -1) yield (i, j)
val largest_ij = ij.find { case(i,j) =>
val product = i * j
if (product.toString == product.toString.reverse)
largest = largest max product
largest > product
}
println(largest_ij.get)
println(largest)
// import following package
import scala.util.control._
// create a Breaks object as follows
val loop = new Breaks;
// Keep the loop inside breakable as follows
loop.breakable{
// Loop will go here
for(...){
....
// Break will go here
loop.break;
}
}
usar el módulo de ruptura http://www.tutorialspoint.com/scala/scala_break_statement.htm
import scala.util.control._
object demo_brk_963
{
def main(args: Array[String])
{
var a = 0;
var b = 0;
val numList1 = List(1,2,3,4,5,6,7,8,9,10);
val numList2 = List(11,12,13);
val outer = new Breaks; //object for break
val inner = new Breaks; //object for break
outer.breakable // Outer Block
{
for( a <- numList1)
{
println( "Value of a: " + a);
inner.breakable // Inner Block
{
for( b <- numList2)
{
println( "Value of b: " + b);
if( b == 12 )
{
println( "break-INNER;");
inner.break;
}
}
} // inner breakable
if( a == 6 )
{
println( "break-OUTER;");
outer.break;
}
}
} // outer breakable.
}
}
Método básico para romper el bucle, utilizando la clase Breaks. Al declarar el bucle como rompible.