¿Cómo salgo de un bucle en Scala?

¿Cómo rompo un bucle?

var largest=0 for(i<-999 to 1 by -1) { for (jproduct) // I want to break out here else if(product.toString.equals(product.toString.reverse)) largest=largest max product } } 

¿Cómo convierto nesteds para bucles en recursividad de cola?

De Scala Talk en FOSDEM 2009 http://www.slideshare.net/Odersky/fosdem-2009-1013261 en la página 22:

Rompe y continúa Scala no los tiene. ¿Por qué? Ellos son un poco imperativos; utilice mejor muchas funciones más pequeñas Emita cómo interactuar con cierres. ¡No son necesarios!

¿Cuál es la explicación?

    Tienes tres (o más) opciones para salir de los bucles.

    Supongamos que quiere sumr números hasta que el total sea mayor que 1000. Intenta

     var sum = 0 for (i < - 0 to 1000) sum += i 

    excepto que quiere detener cuando (sum> 1000).

    ¿Qué hacer? Hay varias opciones.

    (1a) Usa algún constructo que incluya un condicional que pruebes.

     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 takeWhile y foreach durante la evaluación, y probablemente no se deberían usar en la práctica).

    (1b) Use recursividad de cola en lugar de un ciclo 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) Volver a utilizar un ciclo while

     var sum = 0 var i = 0 while (i < = 1000 && sum <= 1000) { sum += 1; i += 1 } 

    (2) Lanza 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 syntax que se parece mucho a su antigua ruptura familiar de C / Java:

     import scala.util.control.Breaks._ var sum = 0 breakable { for (i < - 0 to 1000) { sum += i if (sum >= 1000) break } } 

    (3) Coloque el código en un método y use return.

     var sum = 0 def findSum { for (i < - 0 to 1000) { sum += i; if (sum>=1000) return } } findSum 

    Esto se hizo intencionalmente no demasiado fácil por al menos tres razones que se me ocurren. En primer lugar, en bloques de código grandes, es fácil pasar por alto las afirmaciones de "continuar" y "romper", o pensar que estás saliendo de más o menos de lo que realmente eres, o necesitar romper dos bucles que no puedes hacer fácilmente de todos modos, por lo que el uso estándar, aunque práctico, tiene sus problemas, y por lo tanto, debe tratar de estructurar su código de una manera diferente. En segundo lugar, Scala tiene todo tipo de anidamientos que probablemente ni siquiera notará, por lo que si pudiera salir de allí, probablemente se sorprendería de dónde terminó el flujo de código (especialmente con cierres). Tercero, la mayoría de los "bucles" de Scala no son bucles normales, son llamadas de método que tienen su propio bucle, o son recursiones que pueden o no ser un bucle, y aunque actúan como bucles, es difícil para llegar a una forma consistente de saber qué debería hacer "romper" y cosas por el estilo. Entonces, para ser consecuente, lo más inteligente es no tener ningún "descanso".

    Nota : hay equivalentes funcionales de todos estos en los que devuelve el valor de sum lugar de mutarlo en su lugar. Estos son más idiomáticos Scala. Sin embargo, la lógica sigue siendo la misma. (el return convierte en return x , etc.).

    Esto ha cambiado en Scala 2.8, que tiene un mecanismo para usar descansos. Ahora puede 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 } } } 

    Nunca es una buena idea salir de un bucle for. Si está utilizando un bucle for, significa que sabe cuántas veces quiere iterar. Use un ciclo while con 2 condiciones.

    por ejemplo

     var done = false while (i < = length && !done) { if (sum > 1000) { done = true } } 

    Para agregar Rex Kerr responde de otra manera:

    • (1c) También puedes usar un guardia en tu bucle:

        var sum = 0 for (i < - 0 to 1000 ; if sum<1000) sum += i 

    Como todavía no hay una break en Scala, puede intentar resolver este problema utilizando una return retorno. Por lo tanto, necesita poner su bucle interno en una función, de lo contrario, la vuelta saltaría 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

    Solo usa un ciclo while:

     var (i, sum) = (0, 0) while (sum < 1000) { sum += i i += 1 } 
     // 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; } } 

    utilice el módulo Break http://www.tutorialspoint.com/scala/scala_break_statement.htm

    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 @RexKerr de Stream )

     var sum = 0 for ( i < - Iterator.from(1).takeWhile( _ => sum < 1000) ) sum += i 

    Aquí hay una versión recursiva de cola. Comparado con las for-comprehensions, es un poco críptico, lo admito, pero yo 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 contrapartida de las comprensiones externas, y tr1 de la interna. De nada si conoce una forma de optimizar mi versión.

    Cerca de tu solución serí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 j-iteración se realiza sin un nuevo ámbito, y tanto la generación del producto como la condición se hacen en la statement for (no es una buena expresión, no encuentro una mejor). La condición se invierte, lo que es bastante rápido para ese tamaño de 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 reveses adicionales. 🙂 Un enfoque más matemático podría ser más elegante.

    El paquete breakable terceros es una posible alternativa

    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)) 

    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! IMO son los mismos, malas prácticas y una fuente malvada de todo tipo de problemas (y discusiones calientes) y finalmente “considerados dañinos”. Bloque de código estructurado, también en este ejemplo, los saltos son superfluos. Nuestro Edsger W. Dijkstra † escribió:

    La calidad de los progtwigdores es una función decreciente de la densidad de ir a declaraciones en los progtwigs que producen.

    El uso inteligente del método Find para la colección hará el truco para usted.

     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) 

    Tengo una situación como la 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 una lib de java y el mecanismo es que ctx.read lanza una excepción cuando no puede encontrar nada. Estaba atrapado en la situación de que: tengo que romper el ciclo cuando se lanzó una Excepción, pero scala.util.control.Breaks.break usando Exception para romper el ciclo, y estaba en el bloque catch, así fue capturado.

    Tengo una manera fea de resolver esto: hacer el ciclo por primera vez y obtener el recuento de la longitud real. y usarlo para el segundo ciclo.

    tomar descanso de Scala no es tan bueno, cuando estás usando algunas librerías de Java.

    Soy nuevo en Scala, pero ¿qué tal esto para evitar arrojar excepciones y repetir 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); 

    Úselo 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) }); 
     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 ciclo, usando la clase Breaks. Al declarar el bucle como rompible.

    Simplemente podemos hacer en Scala is

     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