Come faccio a uscire da un ciclo in Scala?

Come faccio a uscire da un ciclo?

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

Come faccio a fare in modo che i loop vengano annidati in ricorsione a coda?

Dalla Scala Talk al FOSDEM 2009 http://www.slideshare.net/Odersky/fosdem-2009-1013261 alla 22a pagina:

Rompi e continua Scala non li ha. Perché? Sono un po ‘imperativi; usare meglio molte funzioni più piccole Scopri come interagire con le chiusure. Non sono necessari!

Qual è la spiegazione?

Hai tre (o così) opzioni per uscire dai loop.

Supponiamo di voler sumre i numeri finché il totale è maggiore di 1000. Prova tu

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

tranne che vuoi smettere quando (sum> 1000).

Cosa fare? Ci sono diverse opzioni

(1a) Usa qualche costrutto che include un condizionale che tu provi.

 var sum = 0 (0 to 1000).iterator.takeWhile(_ => sum < 1000).foreach(i => sum+=i) 

(avviso - questo dipende dai dettagli di come il test takeWhile e il foreach sono intercalati durante la valutazione, e probabilmente non dovrebbero essere usati nella pratica!).

(1b) Usa la ricorsione di coda invece di un ciclo for, sfruttando la facilità con cui puoi scrivere un nuovo metodo in Scala:

 var sum = 0 def addTo(i: Int, max: Int) { sum += i; if (sum < max) addTo(i+1,max) } addTo(0,1000) 

(1c) Tornare all'utilizzo di un ciclo while

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

(2) Lanciare un'eccezione.

 object AllDone extends Exception { } var sum = 0 try { for (i <- 0 to 1000) { sum += i; if (sum>=1000) throw AllDone } } catch { case AllDone => } 

(2a) In Scala 2.8+ questo è già pre-impacchettato in scala.util.control.Breaks usando la syntax che assomiglia molto alla vecchia interruzione familiare di C / Java:

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

(3) Inserire il codice in un metodo e utilizzare il reso.

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

Questo è intenzionalmente reso non troppo facile per almeno tre ragioni a cui posso pensare. Innanzitutto, in blocchi di codice di grandi dimensioni, è facile trascurare le dichiarazioni "continua" e "interruzione", o pensare di uscire da più o meno di quello che sei realmente, o di dover interrompere due cicli che non puoi fare facilmente comunque - quindi l'utilizzo standard, a portata di mano, ha i suoi problemi, e quindi dovresti provare a strutturare il tuo codice in un modo diverso. In secondo luogo, Scala ha tutti i tipi di nidificazione che probabilmente non si notano nemmeno, quindi se si riuscisse a rompere le cose, si sarebbe probabilmente sorpresi da dove finiva il stream di codice (specialmente con le chiusure). In terzo luogo, la maggior parte dei "loop" di Scala non sono in realtà loop normali: sono chiamate di metodo che hanno il loro loop, o sono ricorsioni che possono o meno essere un loop - e sebbene agiscano come loop, è difficile per trovare un modo coerente per sapere cosa dovrebbero fare "break" e simili. Quindi, per essere coerenti, la cosa più saggia da fare è non avere una "pausa".

Nota : ci sono equivalenti funzionali di tutti questi in cui si restituisce il valore della sum piuttosto che la si modifica in posizione. Questi sono più idiomatici di Scala. Tuttavia, la logica rimane la stessa. (il return diventa il return x , ecc.).

Questo è cambiato in Scala 2.8 che ha un meccanismo per usare le pause. Ora puoi fare quanto segue:

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

Non è mai una buona idea uscire da un ciclo. Se stai usando un ciclo for significa che sai quante volte vuoi iterare. Usa un ciclo while con 2 condizioni.

per esempio

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

Per aggiungere Rex Kerr rispondi in un altro modo:

  • (1c) Puoi anche usare una guardia nel tuo loop:

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

Dal momento che non c’è ancora break in Scala, potresti provare a risolvere questo problema con l’uso di una dichiarazione di return . Pertanto è necessario inserire il ciclo interno in una funzione, altrimenti il ​​ritorno salterà l’intero ciclo.

Scala 2.8 tuttavia include un modo per rompere

http://www.scala-lang.org/api/rc/scala/util/control/Breaks.html

Basta usare 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; } } 

usa il modulo Break http://www.tutorialspoint.com/scala/scala_break_statement.htm

Un approccio che genera i valori su un intervallo mentre iteriamo, fino a una condizione di rottura, invece di generare prima un intero intervallo e quindi iterarlo su di esso, usando Iterator , (ispirato all’utilizzo di Stream @RexKerr)

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

Ecco una versione ricorsiva della coda. Rispetto alle incomprensioni è un po ‘criptico, bisogna ammetterlo, ma direi che è funzionale 🙂

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

Come puoi vedere, la funzione tr è la controparte delle incomprensioni esterne, e tr1 di quella interna. Prego, se conosci un modo per ottimizzare la mia versione.

Vicino alla tua soluzione sarebbe questo:

 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-iteration è fatta senza un nuovo scope, e la generazione del prodotto e la condizione sono fatte nell'istruzione for (non una buona espressione - non ne trovo una migliore). La condizione è invertita, il che è abbastanza veloce per quella dimensione del problema - forse si guadagna qualcosa con una pausa per i loop più grandi.

String.reverse converte implicitamente in RichString, che è il motivo per cui eseguo 2 inversioni extra. 🙂 Un approccio più matematico potrebbe essere più elegante.

Il pacchetto breakable terze parti è una ansible alternativa

https://github.com/erikerlandson/breakable

Codice di esempio:

 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)] = [email protected] 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)) 

Ironicamente l’interruzione di Scala in scala.util.control.Breaks è un’eccezione:

 def break(): Nothing = { throw breakException } 

Il miglior consiglio è: NON usare break, continue e goto! IMO sono la stessa, ctriggers pratica e una fonte malvagia di tutti i tipi di problemi (e discussioni scottanti) e infine “considerati dannosi”. Il blocco di codice strutturato, anche in questo esempio, le interruzioni sono superflui. Il nostro Edsger W. Dijkstra † ha scritto:

La qualità dei programmatori è una funzione decrescente della densità delle dichiarazioni go nei programmi che producono.

L’ uso intelligente del metodo di find per la raccolta farà il trucco per te.

 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) 

Ho una situazione come il codice qui sotto

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

Sto usando una java lib e il meccanismo è che ctx.read lancia un’eccezione quando non riesce a trovare nulla. Ero intrappolato nella situazione: Devo interrompere il ciclo quando è stata lanciata un’eccezione, ma scala.util.control.Breaks.break utilizzando Exception per interrompere il ciclo ed era nel blocco catch, quindi è stato catturato.

Ho un modo brutto per risolvere questo problema: fai il ciclo per la prima volta e ottieni il conteggio della lunghezza reale. e usarlo per il secondo ciclo.

prendere una pausa da Scala non è buono, quando si usano alcune librerie java.

Sono nuovo di Scala, ma come fare per evitare di lanciare eccezioni e ripetere i metodi:

 object awhile { def apply(condition: () => Boolean, action: () => breakwhen): Unit = { while (condition()) { action() match { case breakwhen(true) => return ; case _ => { }; } } } case class breakwhen(break:Boolean); 

usalo in questo modo:

 var i = 0 awhile(() => i < 20, () => { i = i + 1 breakwhen(i == 5) }); println(i) 

se non vuoi rompere:

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

Metodo di base per interrompere il ciclo, usando la class Breaks. Dichiarando il loop come fragile.

Semplicemente possiamo fare in scala è

 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; } } } } } 

produzione :

 scala> TestBreak.main(Array()) 1 2 3 4 5