Jak przerwać pętlę?
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
}
}
Jak przekształcić zagnieżdżone pętle w rekurencję ogona?
Z Scala Talk na FOSDEM 2009 http://www.slideshare.net/Odersky/fosdem-2009-1013261 na 22 stronie:
Przerwij i kontynuuj Scala ich nie ma. Czemu? Są nieco konieczne; lepiej korzystać z wielu mniejszych funkcji Problem z interakcją z zamknięciami. Nie są potrzebne!
Jakie jest wyjaśnienie?
scala
for-loop
break
tail-recursion
TiansHUo
źródło
źródło
i
ij
. Jeśli ten kod działa do końca bez wyłamania się z pętli, wynikiem jest wcześniejsze906609
wyłamanie się z pętli, więc wynik jest90909
taki, że wyłamanie się z pętli nie czyni kodu „bardziej wydajnym”, ponieważ zmienia wynik.Odpowiedzi:
Masz trzy (lub mniej więcej) opcje wyjścia z pętli.
Załóżmy, że chcesz sumować liczby, aż suma będzie większa niż 1000. Próbujesz
z wyjątkiem tego, że chcesz zatrzymać kiedy (suma> 1000).
Co robić? Istnieje kilka opcji.
(1a) Użyj konstrukcji, która zawiera testowany warunek.
(ostrzeżenie - zależy to od szczegółów przeplatania testu takeWhile i foreach podczas oceny i prawdopodobnie nie powinno się go stosować w praktyce!).
(1b) Użyj rekurencji ogona zamiast pętli for, wykorzystując łatwość napisania nowej metody w Scali:
(1c) Wróć do korzystania z pętli while
(2) Rzuć wyjątek.
(2a) W Scali 2.8+ jest to już wstępnie spakowane przy
scala.util.control.Breaks
użyciu składni, która wygląda bardzo podobnie do twojej starej starej przerwy w C / Java:(3) Umieść kod w metodzie i użyj return.
Jest to celowo niezbyt łatwe z co najmniej trzech powodów, o których mogę myśleć. Po pierwsze, w dużych blokach kodu łatwo jest przeoczyć instrukcje „kontynuuj” i „zepsuć” lub myśleć, że wychodzisz z mniej lub bardziej niż naprawdę, lub musisz przerwać dwie pętle, których nie możesz zrobić i tak łatwo - więc standardowe użycie, chociaż przydatne, ma swoje problemy, dlatego powinieneś spróbować ustrukturyzować swój kod w inny sposób. Po drugie, Scala ma różnego rodzaju zagnieżdżenia, których prawdopodobnie nawet nie zauważasz, więc jeśli mógłbyś się wyrwać, prawdopodobnie byłbyś zaskoczony, gdzie skończył się przepływ kodu (szczególnie z zamknięciami). Po trzecie, większość „pętli” Scali nie jest tak naprawdę normalnymi pętlami - to wywołania metod, które mają swoją własną pętlę,Pętla, trudno jest znaleźć spójny sposób, aby wiedzieć, co powinno zrobić „zerwanie” i tym podobne. Aby być konsekwentnym, mądrzejszym rozwiązaniem jest wcale nie mieć „przerwy”.
Uwaga : Istnieją funkcjonalne odpowiedniki wszystkich tych funkcji, w których zwracana jest wartość
sum
zamiast mutowania jej w miejscu. Są to bardziej idiomatyczne Scala. Jednak logika pozostaje taka sama. (return
staje sięreturn x
itp.).źródło
breakable
dziale ... i wszystkich tych obręczach, żeby uniknąć złabreak
, hmm ;-) Musisz przyznać, że życie jest ironiczne.break
] Jeśli wygląda jak abreak
i działa jakbreak
, jeśli o mnie chodzi, tobreak
.Zmieniło się to w Scali 2.8, która ma mechanizm korzystania z przerw. Możesz teraz wykonać następujące czynności:
źródło
Nigdy nie jest dobrym pomysłem wyjście z pętli for. Jeśli używasz pętli for, oznacza to, że wiesz, ile razy chcesz iterować. Użyj pętli while z 2 warunkami.
na przykład
źródło
Aby dodać Rex Kerr, odpowiedz w inny sposób:
(1c) Możesz również użyć osłony w swojej pętli:
źródło
Ponieważ nie ma
break
jeszcze Scali, możesz spróbować rozwiązać ten problem za pomocąreturn
-statement. Dlatego musisz włączyć wewnętrzną pętlę do funkcji, w przeciwnym razie powrót pomija całą pętlę.Scala 2.8 zawiera jednak sposób na złamanie
http://www.scala-lang.org/api/rc/scala/util/control/Breaks.html
źródło
użyj modułu Break http://www.tutorialspoint.com/scala/scala_break_statement.htm
źródło
Wystarczy użyć pętli while:
źródło
Podejście, które generuje wartości w całym zakresie podczas iteracji, aż do warunku zerwania, zamiast generowania najpierw całego zakresu, a następnie iteracji nad nim przy użyciu
Iterator
(zainspirowany użyciem @RexKerrStream
)źródło
Oto wersja rekurencyjna. W porównaniu ze zrozumieniem jest to nieco tajemnicze, co prawda, ale powiedziałbym, że jest funkcjonalne :)
Jak widać, funkcja tr jest odpowiednikiem zewnętrznego zrozumienia, a tr1 wewnętrznego. Nie ma za co, jeśli znasz sposób na optymalizację mojej wersji.
źródło
Blisko twojego rozwiązania byłoby to:
J-iteracja jest wykonywana bez nowego zakresu, a generowanie produktu i warunek są wykonywane w instrukcji for (nie jest to dobre wyrażenie - nie znajduję lepszego). Warunek jest odwrócony, co jest dość szybkie jak na ten problem - może zyskujesz coś z przerwą na większe pętle.
String.reverse domyślnie konwertuje na RichString, dlatego robię 2 dodatkowe odwrotności. :) Bardziej matematyczne podejście może być bardziej eleganckie.
źródło
breakable
Pakiet innej firmy jest jedną z możliwych opcjihttps://github.com/erikerlandson/breakable
Przykładowy kod:
źródło
Podstawowa metoda przerywania pętli za pomocą klasy Breaks. Deklarując, że pętla jest przerywalna.
źródło
Po prostu możemy to zrobić w scala jest
wynik :
źródło
Jak na ironię włamanie do Scali
scala.util.control.Breaks
jest wyjątkiem:Najlepsza rada: NIE używaj break, kontynuuj i gotowe! IMO to ta sama, zła praktyka i złe źródło wszelkiego rodzaju problemów (i gorących dyskusji) i wreszcie „uważane za szkodliwe”. Struktura bloku kodu, również w tym przykładzie przerwy są zbędne. Nasz Edsger W. Dijkstra † napisał:
źródło
Mam sytuację taką jak poniższy kod
Używam biblioteki Java, a mechanizm polega na tym, że ctx.read zgłasza wyjątek, gdy nic nie może znaleźć. Byłem uwięziony w sytuacji, w której: musiałem przerwać pętlę, gdy został zgłoszony wyjątek, ale scala.util.control.Breaks.break użył wyjątku, aby przerwać pętlę, i był on w bloku catch, więc został złapany.
Mam brzydki sposób na rozwiązanie tego problemu: wykonaj pętlę po raz pierwszy i oblicz rzeczywistą długość. i użyj go do drugiej pętli.
wziąć przerwę od Scali nie jest tak dobre, gdy używasz niektórych bibliotek Java.
źródło
Jestem nowy w Scali, ale co powiesz na to, aby uniknąć zgłaszania wyjątków i powtarzania metod:
użyj tego w ten sposób:
jeśli nie chcesz się zepsuć:
źródło
Sprytne użycie
find
metody zbierania załatwi sprawę.źródło
źródło
Nie wiem, jak bardzo zmienił się styl Scali w ciągu ostatnich 9 lat, ale uznałem za interesujące, że większość istniejących odpowiedzi używa
vars
lub trudna do odczytania rekurencja. Kluczem do wcześniejszego wyjścia jest użycie leniwej kolekcji do wygenerowania potencjalnych kandydatów, a następnie osobne sprawdzenie stanu. Aby wygenerować produkty:Następnie, aby znaleźć pierwszy palindrom z tego widoku bez generowania każdej kombinacji:
Aby znaleźć największy palindrom (chociaż lenistwo nie kupuje zbyt wiele, ponieważ i tak musisz sprawdzić całą listę):
Twój oryginalny kod w rzeczywistości sprawdza pierwszy palindrom, który jest większy niż kolejny produkt, co jest tym samym, co sprawdzanie pierwszego palindromu, z wyjątkiem dziwnych warunków brzegowych, których nie sądzę, że zamierzałeś. Produkty nie zmniejszają się ściśle monotonicznie. Na przykład
998*998
jest większy niż999*997
, ale pojawia się znacznie później w pętlach.W każdym razie zaletą oddzielnego leniwego generowania i sprawdzania stanu jest to, że piszesz je tak, jakby używało całej listy, ale generuje tylko tyle, ile potrzebujesz. Dostajesz to, co najlepsze z obu światów.
źródło