Wie breche ich eine Schleife aus?
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
}
}
Wie verwandle ich verschachtelte for-Schleifen in Schwanzrekursion?
Aus Scala Talk auf der FOSDEM 2009 http://www.slideshare.net/Odersky/fosdem-2009-1013261 auf der 22. Seite:
Brechen Sie und fahren Sie fort Scala hat sie nicht. Warum? Sie sind ein bisschen zwingend erforderlich; Verwenden Sie besser viele kleinere Funktionen. Fragen Sie, wie Sie mit Verschlüssen interagieren. Sie werden nicht benötigt!
Was ist die Erklärung?
scala
for-loop
break
tail-recursion
TiansHUo
quelle
quelle
i
und zu findenj
. Wenn dieser Code vollständig ausgeführt wird, ohne aus der Schleife906609
auszubrechen, führt90909
dies dazu, dass der Code durch frühzeitiges Ausbrechen aus der Schleife nicht "effizienter" wird, da das Ergebnis geändert wird.Antworten:
Sie haben drei (oder so) Optionen, um aus Schleifen auszubrechen.
Angenommen, Sie möchten Zahlen summieren, bis die Summe größer als 1000 ist. Sie versuchen es
außer Sie möchten aufhören, wenn (Summe> 1000).
Was ist zu tun? Es gibt mehrere Möglichkeiten.
(1a) Verwenden Sie ein Konstrukt, das eine von Ihnen getestete Bedingung enthält.
(Warnung - dies hängt von Details ab, wie der takeWhile-Test und der foreach während der Auswertung verschachtelt sind, und sollte in der Praxis wahrscheinlich nicht verwendet werden!).
(1b) Verwenden Sie die Schwanzrekursion anstelle einer for-Schleife, um zu nutzen, wie einfach es ist, eine neue Methode in Scala zu schreiben:
(1c) Verwenden Sie eine while-Schleife
(2) Eine Ausnahme auslösen.
(2a) In Scala 2.8+ ist dies bereits in einer
scala.util.control.Breaks
Syntax vorgepackt, die Ihrer bekannten alten Pause von C / Java sehr ähnlich sieht:(3) Fügen Sie den Code in eine Methode ein und verwenden Sie return.
Dies wird absichtlich aus mindestens drei Gründen, die mir einfallen, nicht allzu einfach gemacht. Erstens ist es in großen Codeblöcken leicht, die Anweisungen "continue" und "break" zu übersehen oder zu glauben, dass Sie mehr oder weniger ausbrechen, als Sie wirklich sind, oder zwei Schleifen brechen müssen, was Sie nicht können sowieso einfach - so hat die Standardverwendung, obwohl sie praktisch ist, ihre Probleme, und deshalb sollten Sie versuchen, Ihren Code anders zu strukturieren. Zweitens hat Scala alle Arten von Verschachtelungen, die Sie wahrscheinlich gar nicht bemerken. Wenn Sie also aus den Dingen ausbrechen könnten, wären Sie wahrscheinlich überrascht, wo der Codefluss endete (insbesondere bei Schließungen). Drittens sind die meisten "Schleifen" von Scala keine normalen Schleifen - es handelt sich um Methodenaufrufe mit einer eigenen Schleife.Schleifenartig ist es schwierig, einen konsistenten Weg zu finden, um zu wissen, was "Pause" und dergleichen tun sollten. Um konsequent zu sein, ist es klüger, überhaupt keine "Pause" zu machen.
Hinweis : Es gibt funktionale Äquivalente von all diesen, bei denen Sie den Wert von zurückgeben,
sum
anstatt ihn an Ort und Stelle zu mutieren. Dies sind eher idiomatische Scala. Die Logik bleibt jedoch gleich. (return
wirdreturn x
usw.).quelle
breakable
Abschnitt zu werfen ... und all diese Reifen, nur um das Böse zu vermeidenbreak
, hmm ;-) Man muss zugeben, das Leben ist ironisch.break
], wenn es wie a aussiehtbreak
und es funktioniert wie einbreak
, soweit es mich betrifft, ist es einbreak
.Dies hat sich in Scala 2.8 geändert, das über einen Mechanismus zur Verwendung von Pausen verfügt. Sie können jetzt Folgendes tun:
quelle
Es ist niemals eine gute Idee, aus einer for-Schleife auszubrechen. Wenn Sie eine for-Schleife verwenden, bedeutet dies, dass Sie wissen, wie oft Sie iterieren möchten. Verwenden Sie eine while-Schleife mit 2 Bedingungen.
beispielsweise
quelle
Um Rex Kerr hinzuzufügen, antworten Sie auf eine andere Weise:
(1c) Sie können auch einen Schutz in Ihrer Schleife verwenden:
quelle
Da es
break
in Scala noch keine gibt, können Sie versuchen, dieses Problem mit einerreturn
Anweisung zu lösen . Daher müssen Sie Ihre innere Schleife in eine Funktion einfügen, da sonst die Rückgabe die gesamte Schleife überspringen würde.Scala 2.8 enthält jedoch eine Möglichkeit zum Brechen
http://www.scala-lang.org/api/rc/scala/util/control/Breaks.html
quelle
Verwenden Sie das Break-Modul http://www.tutorialspoint.com/scala/scala_break_statement.htm
quelle
Verwenden Sie einfach eine while-Schleife:
quelle
Ein Ansatz, der die Werte über einen Bereich generiert, während wir bis zu einer Unterbrechungsbedingung iterieren, anstatt zuerst einen ganzen Bereich zu generieren und dann mit
Iterator
(iteriert in @RexKerr use ofStream
) darüber zu iterieren.quelle
Hier ist eine rekursive Schwanzversion. Im Vergleich zu den Vorverständnissen ist es zwar ein bisschen kryptisch, aber ich würde sagen, es ist funktional :)
Wie Sie sehen können, ist die tr-Funktion das Gegenstück zum äußeren Verständnis und tr1 zum inneren. Sie sind herzlich willkommen, wenn Sie eine Möglichkeit kennen, meine Version zu optimieren.
quelle
In der Nähe Ihrer Lösung wäre dies:
Die j-Iteration wird ohne neuen Bereich durchgeführt, und die Produktgenerierung sowie die Bedingung werden in der for-Anweisung ausgeführt (kein guter Ausdruck - ich finde keinen besseren). Der Zustand ist umgekehrt, was für diese Problemgröße ziemlich schnell ist - vielleicht gewinnen Sie etwas mit einer Pause für größere Schleifen.
String.reverse konvertiert implizit in RichString, weshalb ich zwei zusätzliche Umkehrungen mache. :) Ein mathematischerer Ansatz könnte eleganter sein.
quelle
Das Drittanbieterpaket
breakable
ist eine mögliche Alternativehttps://github.com/erikerlandson/breakable
Beispielcode:
quelle
Grundlegende Methode zum Unterbrechen der Schleife mithilfe der Breaks-Klasse. Indem Sie die Schleife als zerbrechlich deklarieren.
quelle
Einfach können wir in scala machen
Ausgabe :
quelle
Ironischerweise ist der Einbruch der Scala
scala.util.control.Breaks
eine Ausnahme:Der beste Rat ist: NICHT Pause verwenden, fortfahren und loslegen! IMO sind sie die gleiche, schlechte Praxis und eine böse Quelle aller Arten von Problemen (und heißen Diskussionen) und schließlich "als schädlich angesehen". Codeblock strukturiert, auch in diesem Beispiel sind Unterbrechungen überflüssig. Unser Edsger W. Dijkstra † schrieb:
quelle
Ich habe eine Situation wie den folgenden Code
Ich benutze eine Java-Bibliothek und der Mechanismus ist, dass ctx.read eine Ausnahme auslöst, wenn es nichts finden kann. Ich war in der Situation gefangen, dass: Ich muss die Schleife brechen, wenn eine Ausnahme ausgelöst wurde, aber scala.util.control.Breaks.break verwendet Exception, um die Schleife zu unterbrechen, und sie befand sich im catch-Block, sodass sie abgefangen wurde.
Ich habe einen hässlichen Weg gefunden, dies zu lösen: Mach die Schleife zum ersten Mal und zähle die tatsächliche Länge. und benutze es für die zweite Schleife.
Eine Pause von Scala zu machen ist nicht so gut, wenn Sie einige Java-Bibliotheken verwenden.
quelle
Ich bin neu in Scala, aber wie wäre es damit, Ausnahmen zu vermeiden und Methoden zu wiederholen:
benutze es so:
wenn du nicht brechen willst:
quelle
Die geschickte Anwendung der
find
Sammelmethode erledigt den Trick für Sie.quelle
quelle
Ich weiß nicht, wie sehr sich der Scala-Stil in den letzten 9 Jahren geändert hat, aber ich fand es interessant, dass die meisten vorhandenen Antworten eine
vars
Rekursion verwenden oder schwer zu lesen sind. Der Schlüssel zum vorzeitigen Beenden besteht darin, eine faule Sammlung zu verwenden, um mögliche Kandidaten zu generieren, und dann die Bedingung separat zu prüfen. So generieren Sie die Produkte:Um dann das erste Palindrom aus dieser Ansicht zu finden, ohne jede Kombination zu generieren:
So finden Sie das größte Palindrom (obwohl Ihnen die Faulheit nicht viel kostet, weil Sie sowieso die gesamte Liste überprüfen müssen):
Ihr ursprünglicher Code sucht tatsächlich nach dem ersten Palindrom, das größer als ein nachfolgendes Produkt ist. Dies entspricht der Suche nach dem ersten Palindrom, außer in einer seltsamen Randbedingung, die Sie meiner Meinung nach nicht beabsichtigt haben. Die Produkte nehmen nicht streng monoton ab. Ist zum Beispiel
998*998
größer als999*997
, erscheint aber viel später in den Schleifen.Der Vorteil der getrennten verzögerten Generierungs- und Bedingungsprüfung besteht darin, dass Sie sie so schreiben, als würde sie die gesamte Liste verwenden, aber nur so viel generieren, wie Sie benötigen. Sie bekommen sozusagen das Beste aus beiden Welten.
quelle