Die if-Anweisung
Eine if-Anweisung führt in R einen Codeblock nur aus, wenn eine Bedingung TRUE ist. Die Bedingung steht in runden Klammern, der Code in geschweiften, und ein optionales else liefert, was andernfalls passiert:
Die Bedingung score >= 60 ergibt ein einzelnes TRUE, also läuft der erste Zweig. Die Vergleichs- und logischen Operatoren - ==, >=, &&, %in% und Co. - sind das, woraus du diese Bedingungen baust.
Für mehr als zwei Ausgänge hängst du Prüfungen mit else if an. R läuft die Kette von der ersten Bedingung abwärts und führt den ersten Zweig aus, dessen Bedingung TRUE ist, und überspringt den Rest:
Die Reihenfolge zählt: Weil 85 >= 80 vor 85 >= 70 geprüft wird, ist die Note "B". Sortiertest du die Prüfungen andersherum, bekäme jede Punktzahl über 70 ein "C".
Die Klammer-Falle: Wo else stehen muss
Das ist der Fehler, der fast jedes erste R-Skript erwischt. In einem Skript (oder allem, was mit Rscript läuft) muss else in derselben Zeile stehen wie die schließende Klammer des vorangehenden Zweigs. Das scheitert:
if (score >= 60) {
print("You passed")
}
else { # Error: unexpected 'else'
print("Try again")
}
Warum: R parst Anweisung für Anweisung. Erreicht es das } am Zeilenanfang, ist die if-Anweisung syntaktisch vollständig, und R wertet sie auf der Stelle aus. Das else in der nächsten Zeile kommt als Beginn einer neuen Anweisung an - und eine Anweisung kann nicht mit else beginnen. Die Lösung ist das Muster, das auf dieser ganzen Seite verwendet wird:
if (score >= 60) {
print("You passed")
} else { # brace and else on the same line
print("Try again")
}
Innerhalb eines Funktionsrumpfs oder beliebiger äußerer geschweifter Klammern lockert sich die strenge Regel (R liest weiter, bis die äußere Klammer schließt), aber verlass dich nicht darauf - der Stil } else { funktioniert überall und ist das, was R-Styleguides vorschreiben.
Die Bedingung muss ein einzelnes TRUE oder FALSE sein
if() verlangt genau einen logischen Wert. Zwei Dinge verletzen das, und beide sind Fehler:
if (NA) print("hi")
# Error: missing value where TRUE/FALSE needed
if (c(TRUE, FALSE)) print("hi")
# Error: the condition has length > 1
Der NA-Fall zählt in der Praxis, weil Vergleiche mit fehlenden Daten NA erzeugen: Ist x gleich NA, dann ist x > 10 gleich NA, und ein if mit dieser Bedingung stoppt dein Skript. Das defensive Muster nutzt das verkürzt auswertende &&:
Weil !is.na(x) gleich FALSE ist, wird der Teil x > 10 nie ausgewertet und kein NA erreicht die Bedingung. Wie sich NA durch Vergleiche fortpflanzt, wird unter fehlende Werte behandelt.
Der Fehler "Länge größer 1" (seit R 4.2 durchgesetzt; davor nutzte R stillschweigend das erste Element) bedeutet meist, dass du eigentlich eines davon meintest: any(v > 5), wenn ein Treffer genügt, all(v > 5), wenn jedes Element bestehen muss, oder ifelse(), wenn du eine Antwort pro Element wolltest - das ist der nächste Abschnitt.
ifelse(): vektorisiertes If Else
if entscheidet einmal. ifelse(test, yes, no) entscheidet für jedes Element eines Vektors und gibt einen Vektor gleicher Länge zurück:
Jedes Element von temps wird unabhängig geprüft: "hot" "mild" "mild" "hot" "mild". Das ist das Werkzeug, um einen neuen Vektor oder eine neue Data-Frame-Spalte aus einer bestehenden abzuleiten - ganz ohne Schleife.
Anders als if geht ifelse() elegant mit fehlenden Werten um: Ein NA im Test ergibt ein NA im Resultat statt eines Fehlers:
Du kannst ifelse()-Aufrufe für Dreifachverzweigungen verschachteln, und in dieser Tiefe bleibt es noch lesbar:
Aber hör da auf. Drei oder mehr verschachtelte ifelse()-Aufrufe werden zu einem Klammer-Puzzle; ab dann greif zu cut() (für numerische Bereiche) oder dplyr::case_when(), das jede Bedingung in eine eigene Zeile stellt.
switch() für Mehrfachverzweigungen
Wenn du einen Wert gegen eine Liste bekannter Namen abgleichst - keine Bereiche prüfst -, ist eine lange else if-Kette das plumpe Werkzeug. switch() sagt es direkt:
Drei Verhaltensweisen zum Merken:
- Abgleich:
switch()vergleicht den Zeichenwert mit den Argumentnamen und gibt das passende Ergebnis zurück. - Durchfallen: Ein Name mit leerer rechter Seite (
sat = ,) fällt zum Ergebnis des nächsten Falls durch - so teilen sich"sat"und"sun"das"weekend", ohne es zu wiederholen. - Standardwert: Das letzte unbenannte Argument (
"weekday") wird zurückgegeben, wenn nichts passt. Ohne Standardwert gibtswitch()bei einem nicht passenden Wert unsichtbarNULLzurück - deine Funktion liefert still nichts, ein verwirrender Bug. Gib immer einen Standardwert an (oder mach ihn zu einem explizitenstop()).
switch() glänzt in Funktionen, die auf ein Modus- oder Methodenargument verzweigen; für alles, was auf numerischen Schwellen beruht, bleib bei else if oder cut().
Was du mitnimmst
if (condition) { } else { }- Bedingung in Klammern, ein Zweig läuft; mitelse ifverketten, der erste Treffer gewinnt.- In Skripten
} else {in eine Zeile schreiben -elseam Zeilenanfang ist ein Syntaxfehler. if()braucht genau einTRUE/FALSE:NAist ein Fehler, ein längerer Vektor ist ein Fehler (seit R 4.2). Absichern mit!is.na(x) &&oder mitany()/all()reduzieren.ifelse(test, yes, no)ist die vektorisierte Variante - nutze sie, um neue Vektoren zu berechnen, und verschachtle sie nicht mehr als zweimal.switch()erledigt Mehrfachverzweigung über Namen, mit Durchfallen über leere Fälle - gib ihm immer einen Standardwert.
Als Nächstes: etwas mehr als einmal tun - for-Schleifen und wann eine Schleife das richtige Werkzeug ist (und wann nicht).
Häufig gestellte Fragen
Wie schreibt man eine if-else-Anweisung in R?
if (condition) { ... } else { ... } - die Bedingung steht in Klammern und jeder Zweig in geschweiften Klammern. Weitere Prüfungen hängst du mit else if (condition) an. In einem Skript muss else in derselben Zeile stehen wie die schließende Klammer des vorherigen Zweigs (} else {), sonst meldet R unexpected 'else'.
Was ist der Unterschied zwischen if und ifelse() in R?
if ist eine Kontrollflussanweisung, die genau einen TRUE/FALSE-Wert prüft und einen Codezweig ausführt. ifelse(test, yes, no) ist eine vektorisierte Funktion: Sie prüft alle Elemente eines Vektors auf einmal und gibt einen Ergebnisvektor zurück. Nutze if, um zu entscheiden, was dein Programm tut; nutze ifelse(), um aus einer bestehenden Spalte oder einem Vektor eine neue zu berechnen.
Warum sagt R 'the condition has length > 1'?
Du hast if() einen ganzen Vektor übergeben, obwohl es ein einzelnes TRUE oder FALSE braucht. Seit R 4.2 ist das ein Fehler statt einer stillen Verwendung des ersten Elements. Behebe es, indem du den Vektor auf einen Wert reduzierst - any(x > 5), all(x > 5) - oder auf das vektorisierte ifelse() wechselst, falls du ein Ergebnis pro Element wolltest.
Wie funktioniert switch() in R?
switch(value, name1 = result1, name2 = result2, default) vergleicht einen Zeichenwert mit den Argumentnamen und gibt das passende Ergebnis zurück. Ein Name mit leerer rechter Seite fällt zum nächsten Ergebnis durch, sodass mehrere Fälle ein Ergebnis teilen können. Das letzte unbenannte Argument dient als Standardwert; ohne einen solchen gibt ein nicht passender Wert unsichtbar NULL zurück.