Instrukcja if
Instrukcja if w R uruchamia blok kodu tylko wtedy, gdy warunek ma wartość TRUE. Warunek trafia do nawiasów okrągłych, kod do klamrowych, a opcjonalne else mówi, co zrobić w przeciwnym razie:
Warunek score >= 60 daje jedno TRUE, więc uruchamia się pierwsza gałąź. Takie warunki budujesz z operatorów porównania i logicznych: ==, >=, &&, %in% i pokrewnych.
Przy więcej niż dwóch możliwościach łączysz sprawdzenia przez else if. R przechodzi łańcuch od pierwszego warunku w dół i uruchamia pierwszą gałąź, której warunek jest TRUE, a resztę pomija:
Kolejność ma znaczenie: 85 >= 80 jest sprawdzane przed 85 >= 70, więc ocena to "B". Gdyby sprawdzenia stały w odwrotnej kolejności, każdy wynik powyżej 70 dostałby "C".
Pułapka z klamrą: gdzie musi stać else
Ten błąd trafia prawie każdego w pierwszym skrypcie w R. W skrypcie (albo w czymkolwiek uruchamianym przez Rscript) else musi stać w tej samej linii co nawias zamykający poprzedniej gałęzi. To nie zadziała:
if (score >= 60) {
print("You passed")
}
else { # Error: unexpected 'else'
print("Try again")
}
Dlaczego? R analizuje kod instrukcja po instrukcji. Gdy dociera do } na początku linii, instrukcja if jest składniowo kompletna i R od razu ją wykonuje. else w następnej linii trafia jako początek nowej instrukcji, a instrukcja nie może zaczynać się od else. Rozwiązaniem jest wzorzec używany na całej tej stronie:
if (score >= 60) {
print("You passed")
} else { # brace and else on the same line
print("Try again")
}
Wewnątrz ciała funkcji albo dowolnej zewnętrznej pary klamer ta surowa zasada łagodnieje (R czyta dalej, aż zamknie się zewnętrzna klamra), ale nie polegaj na tym. Styl } else { działa wszędzie i to on jest zalecany w przewodnikach stylu R.
Warunek musi być jednym TRUE albo FALSE
if() wymaga dokładnie jednej wartości logicznej. Dwie sytuacje łamią tę zasadę i obie kończą się błędem:
if (NA) print("hi")
# Error: missing value where TRUE/FALSE needed
if (c(TRUE, FALSE)) print("hi")
# Error: the condition has length > 1
Przypadek z NA ma znaczenie w praktyce, bo porównania z brakującymi danymi dają NA: jeśli x to NA, to x > 10 też jest NA, a if z takim warunkiem zatrzymuje skrypt. Wzorzec obronny korzysta ze skróconego &&:
Ponieważ !is.na(x) jest FALSE, część x > 10 nigdy nie jest obliczana i żadne NA nie trafia do warunku. To, jak NA przechodzi przez porównania, opisuje artykuł o brakujących wartościach.
Błąd o długości większej niż 1 (egzekwowany od R 4.2; wcześniej R po cichu brał pierwszy element) zwykle oznacza, że chodziło o coś innego: any(v > 5), jeśli wystarczy jedno dopasowanie, all(v > 5), jeśli każdy element musi spełnić warunek, albo ifelse(), jeśli potrzebna jest odpowiedź dla każdego elementu. O tym jest kolejna sekcja.
ifelse(): wektorowe if else
if decyduje raz. ifelse(test, yes, no) decyduje dla każdego elementu wektora i zwraca wektor tej samej długości:
Każdy element temps jest sprawdzany osobno: "hot" "mild" "mild" "hot" "mild". To narzędzie do wyprowadzania nowego wektora albo kolumny ramki danych z istniejących danych, bez żadnej pętli.
W przeciwieństwie do if, ifelse() łagodnie obsługuje brakujące wartości: NA w teście daje NA w wyniku zamiast błędu:
Wywołania ifelse() można zagnieżdżać przy podziale na trzy grupy i na tym poziomie kod nadal jest czytelny:
Ale na tym poprzestań. Trzy lub więcej zagnieżdżonych ifelse() zamienia się w łamigłówkę z dopasowywaniem nawiasów. Wtedy sięgnij po cut() (dla zakresów liczbowych) albo dplyr::case_when(), który umieszcza każdy warunek w osobnej linii.
switch() do wyboru spośród wielu opcji
Gdy dopasowujesz jedną wartość do listy znanych nazw, a nie sprawdzasz zakresów, długi łańcuch else if jest niezgrabnym narzędziem. switch() mówi to wprost:
Trzy zachowania, które warto znać:
- Dopasowanie:
switch()porównuje wartość tekstową z nazwami argumentów i zwraca pasujący wynik. - Przejście dalej: nazwa z pustą prawą stroną (
sat = ,) przechodzi do wyniku następnego przypadku. Dzięki temu"sat"i"sun"współdzielą"weekend"bez powtarzania. - Wartość domyślna: ostatni nienazwany argument (
"weekday") jest zwracany, gdy nic nie pasuje. Bez wartości domyślnej niedopasowana wartość sprawia, żeswitch()zwraca niewidocznieNULL: funkcja po cichu nic nie zwraca, co jest mylącym błędem. Zawsze podawaj wartość domyślną (albo jawnestop()).
switch() błyszczy wewnątrz funkcji, które wybierają działanie na podstawie argumentu trybu albo metody; przy progach liczbowych zostań przy else if albo cut().
Co warto zapamiętać
if (condition) { } else { }: warunek w nawiasach, uruchamia się jedna gałąź; łańcuch tworzysz przezelse if, wygrywa pierwsze dopasowanie.- W skryptach pisz
} else {w jednej linii, boelsena początku linii to błąd składni. if()potrzebuje dokładnie jednegoTRUE/FALSE:NAto błąd, dłuższy wektor to błąd (od R 4.2). Zabezpieczaj się przez!is.na(x) &&albo redukuj przezany()/all().ifelse(test, yes, no)to wersja wektorowa: używaj jej do wyliczania nowych wektorów i nie zagnieżdżaj więcej niż dwa razy.switch()obsługuje wybór według nazw, z przejściem dalej przez puste przypadki. Zawsze dawaj mu wartość domyślną.
Dalej: robienie czegoś więcej niż raz, czyli pętle for i sytuacje, w których pętla jest (albo nie jest) właściwym narzędziem.
Najczęściej zadawane pytania
Jak napisać instrukcję if else w R?
if (condition) { ... } else { ... }: warunek w nawiasach okrągłych, każda gałąź w klamrowych. Kolejne sprawdzenia dołączasz przez else if (condition). W skrypcie else musi stać w tej samej linii co nawias zamykający poprzedniej gałęzi (} else {), inaczej R zgłasza unexpected 'else'.
Czym różni się if od ifelse() w R?
if to instrukcja sterująca, która sprawdza dokładnie jedną wartość TRUE/FALSE i uruchamia jedną gałąź kodu. ifelse(test, yes, no) to funkcja wektorowa: sprawdza naraz każdy element wektora i zwraca wektor wyników. Używaj if, żeby zdecydować, co robi program, a ifelse(), żeby wyliczyć nową kolumnę albo wektor z istniejącego.
Dlaczego R zgłasza 'the condition has length > 1'?
Przekazano cały wektor do if(), a ta instrukcja potrzebuje jednego TRUE albo FALSE. Od R 4.2 to błąd, a nie ciche użycie pierwszego elementu. Napraw to, redukując wektor do jednej wartości (any(x > 5), all(x > 5)), albo przejdź na wektorowe ifelse(), jeśli chodziło o wynik dla każdego elementu.
Jak działa switch() w R?
switch(value, name1 = result1, name2 = result2, default) porównuje wartość tekstową z nazwami argumentów i zwraca pasujący wynik. Nazwa z pustą prawą stroną przechodzi do kolejnego wyniku, więc kilka przypadków może mieć wspólny rezultat. Ostatni nienazwany argument działa jako wartość domyślna; bez niego niedopasowana wartość zwraca niewidocznie NULL.