scala for-loop break tail-recursion

¿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.