Pętla while
Pętla while w R wykonuje swoje ciało tak długo, jak długo warunek pozostaje TRUE. Pętla for wykonuje się raz dla każdego elementu czegoś, a while wykonuje się nieznaną liczbę razy, aż warunek się zmieni:
Każda pętla while działa dzięki trzem częściom i wszystkie trzy widać tutaj:
- Przygotowanie przed pętlą:
count <- 1daje warunkowi coś do sprawdzenia. - Warunek:
count <= 5, zbudowany ze zwykłych operatorów porównania, sprawdzany przed każdym przebiegiem. - Aktualizacja w ciele:
count <- count + 1przybliża pętlę do zatrzymania.
Usuń część 3, a warunek będzie TRUE na zawsze: pętla nigdy się nie skończy. To podstawowe ryzyko while, a reszta tej strony w dużej mierze dotyczy tego, jak nad nim zapanować.
Warunek jest sprawdzany przed każdym przebiegiem
while najpierw sprawdza warunek, a potem wykonuje ciało. Wynikają z tego dwie rzeczy. Jeśli warunek jest FALSE już na starcie, ciało wykona się zero razy:
Poza tym sprawdzenie odbywa się między pełnymi przebiegami, a nie w środku ciała: gdy przebieg się zacznie, dojdzie do końca, nawet jeśli warunek w połowie stanie się FALSE. Jeśli musisz wyskoczyć w środku ciała, do tego służy break (niżej).
Przykład: dzielenie na pół aż do spadku poniżej progu
Naturalne miejsce dla while to „rób dalej, aż”: nie wiadomo z góry, ile przebiegów będzie potrzebnych, więc for nie pasuje. Ile razy można podzielić 1000 na pół, zanim wynik spadnie poniżej 1?
Dziesięć podziałów, a na końcu około 0.977. Ten wzorzec (zmienna stanu, którą ciało zmniejsza, i licznik, który zwiększa) pokrywa ogromną część prawdziwych pętli while: metody numeryczne działające, aż błąd będzie dostatecznie mały, symulacje działające do wyczerpania zasobu, ponowne próby trwające, aż wywołanie się powiedzie.
repeat + break: do-while w wersji R
R nie ma słowa kluczowego do-while, czyli pętli, która sprawdza warunek po ciele. Ma za to repeat, który wykonuje pętlę bezwarunkowo w nieskończoność, i break, który natychmiast wychodzi z dowolnej pętli. Umieść test z break na końcu ciała repeat, a zbudujesz dokładnie do-while, czyli pętlę, której ciało na pewno wykona się co najmniej raz:
Ciało zawsze wykonuje się przed pierwszym testem, więc n zostaje podwojone co najmniej raz; pętla kończy się na 128, pierwszym podwojeniu powyżej 100. Używaj tego kształtu, gdy uczciwy opis brzmi „zrób to, a potem zdecyduj, czy zrobić to znowu”: wczytywanie danych, aż będą poprawne, losowanie próbek, aż któraś spełni warunek. repeat bez osiągalnego break to z definicji nieskończona pętla, więc najpierw napisz break, a potem uzupełnij ciało.
break działa identycznie w pętlach while i for: to ogólne wyjście „tu kończymy”, które naturalnie łączy się z instrukcjami if sprawdzającymi warunek w środku ciała.
next w pętli while
next pomija resztę bieżącego przebiegu i wraca do sprawdzenia warunku. W while działa tak samo jak w for, z jedną pułapką specyficzną dla while: jeśli krok aktualizacji stoi po next, pominięcie go oznacza, że zmienna pętli nigdy się nie przesunie, a ty masz nieskończoną pętlę. Umieść aktualizację przed next:
To wypisuje liczby parzyste od 2 do 10. Przenieś i <- i + 1 poniżej linii z next, a pierwsza nieparzysta wartość na zawsze pomijałaby aktualizację. W pętlach for to zagrożenie nie istnieje (zmienna pętli przesuwa się automatycznie), co jest kolejnym powodem, żeby wybierać for, gdy po prostu przechodzisz przez ciąg.
Ochrona przed nieskończonymi pętlami
Każda nieskończona pętla to ten sam błąd: nic w ciele nie zmienia zmiennych, od których zależy warunek, albo zmienia je w złym kierunku. W trybie interaktywnym możesz przerwać przez Esc lub Ctrl+C, ale w skrypcie proces po prostu się zawiesza. Zapobiegają temu dwa nawyki.
Po pierwsze, gdy piszesz warunek, od razu zadaj sobie pytanie „która linia ciała przybliża go do FALSE?” i upewnij się, że ta linia wykonuje się na każdej ścieżce przez ciało (uważaj na pułapkę z next opisaną wyżej).
Po drugie, w pętlach, których zakończenia nie da się łatwo udowodnić, dodaj ograniczenie liczby iteracji, żeby błąd logiczny dał wynik, który można zdiagnozować, a nie zamrożoną sesję. Tutaj chroni ono pętlę w stylu Collatza: dziel parzyste liczby na pół, a nieparzyste x zamieniaj na 3 * x + 1, aż dojdziesz do 1:
Zaczynając od 10, pętla dochodzi do 1 w 6 krokach. Gdyby jakaś wartość startowa nigdy nie doszła do 1, warunek steps < 10000 i tak zakończyłby pętlę, a wypisany stan pokazałby, że coś poszło nie tak. Widoczna zła odpowiedź jest lepsza niż program, który nigdy nie odpowiada. Skrócony operator && jest tu właściwy: obie strony to pojedyncze wartości, a ograniczenie czyta się jak jedno zdanie.
while czy for: jak wybrać
Zasada praktyczna dotyczy tego, co wiesz z góry:
- Wiesz, po czym iterujesz (elementy wektora, liczby od 1 do n): użyj pętli for, bo zmienna pętli sama o siebie dba.
- Znasz tylko warunek zatrzymania (aż do zbieżności, aż spadnie poniżej progu, aż będzie poprawne): użyj
while. - Ciało musi wykonać się co najmniej raz, zanim jakikolwiek test ma sens: użyj
repeatz kończącymbreak.
Jeśli w pętli while ręcznie prowadzisz licznik tylko po to, żeby przejść przez wektor, to przebrana pętla for. Zmień ją.
Najważniejsze informacje
while (condition) { ... }najpierw sprawdza, potem wykonuje: fałszywy warunek na starcie oznacza zero przebiegów.- Ciało musi przybliżać warunek do
FALSE; trójka przygotowanie / warunek / aktualizacja to cała dyscyplina. - R nie ma słowa kluczowego do-while: idiomem jest
repeat { body; if (done) break }, który gwarantuje co najmniej jeden przebieg. breakwychodzi z dowolnej pętli; przynextwwhileaktualizuj zmienną pętli przed pominięciem, bo inaczej nigdy się nie przesunie.- Ograniczenie liczby iteracji (
&& steps < 10000) zamienia potencjalne zawieszenie w widoczną złą odpowiedź, którą da się zdebugować.
Dalej: wektory, czyli struktura danych, po której przechodziła każda pętla z tej strony, i powód, dla którego wiele pętli w R może całkowicie zniknąć.
Najczęściej zadawane pytania
Jak działa pętla while w R?
while (condition) { ... } najpierw sprawdza warunek i wykonuje ciało tylko dopóki warunek pozostaje TRUE. Coś w ciele musi w końcu sprawić, że warunek stanie się FALSE (zwykle aktualizacja licznika albo zmniejszanie wartości), bo inaczej pętla nigdy się nie skończy. Jeśli warunek jest FALSE od początku, ciało wykona się zero razy.
Czy R ma pętlę do-while?
Nie jako słowo kluczowe. Idiom to repeat { ...body...; if (condition) break }: repeat wykonuje pętlę bezwarunkowo, więc ciało na pewno wykona się co najmniej raz, a break na końcu pełni rolę testu wyjścia z do-while.
Jak zatrzymać nieskończoną pętlę w R?
W trybie interaktywnym naciśnij Esc (RStudio) albo Ctrl+C (terminal), żeby ją przerwać. Żeby w ogóle do niej nie dopuścić, upewnij się, że ciało przy każdym przebiegu aktualizuje zmienne z warunku, i dodaj ograniczenie liczby iteracji, while (working && steps < 10000), żeby błąd logiczny dał złą liczbę zamiast zamrożonej sesji.