Die for-Schleife in R
Schleifen mit einer Zählvariable werden eingesetzt, wenn bekannt ist, wie oft ein gewisser Vorgang wiederholt werden muss (wobei die Anweisungen nicht exakt identisch sind, sondern meist vom Wert der Zählvariable abhängen). Die Syntax der for-Schleife sowie einige mit ihr verbundene Spitzfindigkeiten werden erklärt. Zusätzliche Kontrolle über den Ablauf einer Schleife erhält man durch break (vorzeitiges Verlassen der Schleife) und next (sofortiger Übergang zum nächsten Wert der Zählvariable).
- Einordnung des Artikels
- Einführung
- Arten von Schleifen
- Die Schleife mit Zählvariable (for-Schleife)
- Bezeichnungen: Schleife, Schleifenkörper, Schleifen-Durchlauf
- Auswahl der Beispiele
- Die Syntax der for-Schleife
- Der einfachste Fall
- Was gehört vor die Schleife, in die Schleife und nach die Schleife?
- Einige Spitzfindigkeiten
- Die geschweiften Klammern
- Die Unveränderlichkeit des Vektors, über den iteriert wird
- Iterierbare Objekte
- Andere Vektoren als (1:n)
- Andere Objekte als Vektoren
- Die Schlüsselwörter break und next
- Verschachtelte Schleifen
- Zusammenfassung
Einordnung des Artikels
- Einführung in die Informatik
- Einführung in die Programmiersprache R
- Kontrollstrukturen in R
- Die for-Schleife in R
- Kontrollstrukturen in R
- Einführung in die Programmiersprache R
Einführung
Arten von Schleifen
Nach der Alternative ist die Schleife (oder Iteration) die wichtigste Kontrollstruktur, die den Ablauf von Programmen regelt. Mit einer Schleife ist gemeint, dass etwas wie eine Liste abgearbeitet werden muss, wobei für jeden Listen-Eintrag dieselben Befehle ausgeführt werden müssen In Pseudocode und formale Sprachen im Abschnitt Schleife (Iteration) wurden
- die kopfgesteuerte Schleife,
- die fußgesteuerte Schleife und
- die Schleife mit Zählvariable
im Pseudocode vorgestellt. Letztere wird in R mit der for-Anweisung realisiert; und da dies diejenige Schleife ist, die am klarsten strukturiert ist, wird sie zuerst besprochen.
Für eine ausführliche Einführung in Schleifen – unabhängig von einer Programmiersprache – ist oben zitierter Abschnitt zu empfehlen.
Die Schleife mit Zählvariable (for-Schleife)
Das Paradebeispiel einer Schleife, das in Pseudocode und formale Sprachen im Abschnitt Schleife (Iteration) diskutiert wird, ist:
Es sollen die Personalien aller sich in einem Raum befindlichen Personen aufgenommen werden.
Das Problem wird zunächst in 2 Teilprobleme zerlegt:
- Was ist zu tun, um von einer Person die Personalien aufzunehmen?
- Wie sorgt man dafür, dass alle Personen durchlaufen werden?
Im Pseudocode lautet die Lösung des Problems etwa
Für i = 1 bis N Schrittweite 1
PersonalienAufnehmen(P(i))
Dabei wird vorausgesetzt:
- Es ist bekannt, dass N Personen im Raum sind.
- Die Personen sind durchnumeriert und können mit P(i), i = 1, 2, ..., N aufgerufen werden.
- Das erste Teilproblem oben ist bereits gelöst: Der Aufruf des Unterprogramms
PersonalienAufnehmen(P(i))
nimmt die Personalien der Person i auf.
Man erkennt dann, wie durch Zeile 1 das zweite Teilproblem gelöst wird:
Es wird eine Zählvariable i eingeführt, über die die Personen aufgerufen werden können. Die Zählvariable läuft von 1 bis N bei einer Schrittweite von 1. Dies garantiert, dass jede Person aufgerufen wird.
Man kann die Schleife auch als Abkürzung für die Folge von N Anweisungen sehen:
PersonalienAufnehmen(P(1))
PersonalienAufnehmen(P(2))
...
PersonalienAufnehmen(P(N))
Da R auf Vektoren basiert, wird auch die Schleife mit Zählvariable über einen Vektor konfiguriert: Man gibt sich einen Vektor seq vor, dessen Komponenten nacheinander von der Zählvariable var angenommen werden. Der Ausdruck expr ist ein beliebiger Block von Anweisungen, der mit jedem Wert von var ausgeführt wird.
for(var in seq) expr
Darum dass nach einem Abarbeiten von expr der nächste Wert von var gesetzt wird und wiederum expr abgearbeitet wird, muss sich der Programmierer nicht kümmern – dies ist gerade die Ausführung der Schleife. (Ebenso, dass die Schleife verlassen wird, wenn var den letzten Wert aus seq angenommen hat und die zugehörigen Anweisungen abgearbeitet wurden.)
Bezeichnungen: Schleife, Schleifenkörper, Schleifen-Durchlauf
Für das Beispiel, das oben im Pseudocode formuliert wurde, nämlich
Für i = 1 bis N Schrittweite 1
PersonalienAufnehmen(P(i))
sollen nun die Bezeichnungen vereinbart werden, die im Folgenden verwendet werden.
Angenommen es befinden sich 7 Personen im Raum, dann sagt man auch gerne, dass die Schleife 7-mal durchlaufen werden muss. Diese Sprechweise ist etwas irreführend und soll nun präzisiert werden.
Die Anweisung PersonalienAufnehmen(P(i))
wird als der Schleifenkörper bezeichnet; weiter unten wird erklärt, dass hier auch mehrere Anweisungen stehen können. Die Anweisungen im Schleifenkörper hängen vom aktuellen Wert der Zählvariable i ab.
Werden jetzt von allen 7 Personen die Personalien aufgenommen, so sollte man besser sagen: Der Schleifenkörper wird 7-mal durchlaufen. Das Aufnehmen der Personalien einer Person wird auch als ein Schleifen-Durchlauf bezeichnet.
Die eigentliche Schleife besteht aus sämtlichen Schleifen-Durchläufen. Wenn die Zählvariable ihren letzten Wert angenommen hat und alle Personen abgearbeitet wurden, wird die Schleife verlassen; es folgen Anweisungen, die nicht mehr zur Schleife gehören.
In salopper Sprechweise wird oft der Begriff Schleife sowohl für die Gesamtheit aller Schleifen-Durchläufe als auch für einen einzigen Schleifen-Durchlauf verwendet. Achten Sie beim Lesen der einschlägigen Literatur an dieser Stelle darauf, wie der Begriff Schleife eingesetzt wird.
Oft – und gleichwertig – wird die Schleife auch als Iteration bezeichnet. Ein Schleifen-Durchlauf ist dann ein Iterationsschritt. Den Schleifenkörper nennt man dann den Körper (oder den Rumpf) der Iteration.
Auswahl der Beispiele
Die Beispiele, mit denen im Folgenden Schleifen erläutert werden, lassen sich in R auch deutlich einfacher realisieren – weil entsprechende Funktionen bereits implementiert sind. Die einfacheren Lösungen werden dann nur verwendet, um eine Kontrollrechnung durchzuführen.
Ziel diese Kapitels ist es natürlich, eine Einführung in Schleifen zu geben und nicht die vorgestellten Aufgaben möglichst einfach zu lösen.
Gerade im Zusammenhang mit Schleifen muss darauf hingewiesen werden, dass es in R die sogenannte Familie von apply()-Funktionen gibt, mit der sich viele Schleifen vermeiden lassen. Diese Familie wird aber erst später besprochen, wenn erklärt wurde, wie man selber Funktionen definiert.
Die Syntax der for-Schleife
Der einfachste Fall
Wie in R eine Schleife allgemein aussieht, wurde oben bereits gezeigt. Die allgemeine Syntax soll jetzt an einem einfachen Beispiel erklärt werden: Die Zahlen von 1 bis 100 werden mit einer for-Schleife addiert.
idx <- (1:100)
summe <- 0
for(i in idx){
summe <- summe + i
}
cat("Summe: ", summe, "\n")
# Summe: 5050
# Kontrolle:
sum(idx)
# [1] 5050
Zeile 1: Es wird der Vektor der Zahlen vorbereitet, die addiert werden sollen.
Zeile 2: Es wird eine Variable summe vorbereitet, die die Zwischensummen berechnet; am Ende der Schleifen-Durchläufe muss sie die Gesamtsumme beinhalten. Diese Hilfsvariable muss natürlich am Anfang den Wert 0 besitzen.
Zeile 4 bis 6: Die eigentliche for-Schleife. Nach dem Schlüsselwort for folgt in runden Klammern die Konfiguration der Schleife:
- Man kann den Namen der Zählvariable selbst bestimmen (hier i).
- Das Schlüsselwort in besagt, dass i alle Werte des folgenden Vektors durchläuft.
- Der Vektor, der durchlaufen wird, sind hier die Zahlen von 1 bis 100, die zuvor in idx abgespeichert wurden. Man hätte statt Zeile 4 natürlich auch schreiben können
for(i in (1:100)){
; der Vektor idx wurde nur eingeführt, um ausdrücklich darauf hinzuweisen, dass hier meist ein Vektor steht. (Welche anderen Objekte anstelle eines Vektors verwendet werden können, wird weiter unten erklärt.)
Zeile 8 und 9: Nach Beendigung der Schleife wird die Variable summe ausgegeben; sie liefert den Wert 5050.
Zeile 11 und 12. Die Kontrollrechnung mit der Funktion sum() liefert den selben Wert.
Was gehört vor die Schleife, in die Schleife und nach die Schleife?
Für das Verständnis des Ablaufs einer Schleife ist es wichtig, sich zu fragen:
- Welche Anweisungen müssen vor der Schleife stehen (und diese vorbereiten)?
- Welche Anweisungen stehen im Schleifenkörper?
- Welche Anweisungen stehen nach der Schleife?
Man kann dazu obiges Beispiel verwenden und die Anweisungen verschieben.
Zuerst wird die Anweisung summe <- 0
in den Schleifenkörper verschoben:
idx <- (1:100)
for(i in idx){
summe <- 0
summe <- summe + i
}
cat("Summe: ", summe, "\n")
# Summe: 100
# Kontrolle:
sum(idx)
# [1] 5050
Wie kann man das Ergebnis 100 erklären?
Wird summe bei jedem Durchlauf der Schleife auf 0 zurückgesetzt, stimmt nach dem Durchlauf einer Schleife summe genau mit dem aktuellen Wert von i überein. Nach dem letzten Durchlauf ist somit summe mit 100 belegt.
Was passiert, wenn die Ausgabe cat("Summe: ", summe, "\n")
in den Schleifenkörper verschoben wird?
idx <- (1:100)
summe <- 0
for(i in idx){
summe <- summe + i
cat("Summe: ", summe, "\n")
}
# Kontrolle:
sum(idx)
# [1] 5050
Jetzt wird bei jedem Schleifen-Durchlauf eine Ausgabe erzeugt, nämlich mit dem aktuellen Wert von summe. Dies ergibt 100 Ausgaben mit den Werten: 1, 3, 6, 10, ..., 5050.
Diese Zwischensummen sind hier irrelevant, gefragt war nur der letzte Zahlenwert von summe. Um die Zwischensummen zu unterdrücken, muss die Ausgabe nach der Schleife erfolgen.
Man kann versuchen, die Antwort auf die Frage "was gehört vor, in und nach die Schleife?" etws allgemeiner zu formulieren:
- Vor die Schleife gehören Anweisungen, die die Schleife vorbereiten, also etwa die Definition von Variablen, die sich auf die Gesamtheit der Schleifen-Durchläufe beziehen. Dies sind meist einmalige Anweisungen, die nicht wiederholt werden.
- In den Schleifenkörper gehören Anweisungen, die bei jedem Durchlauf ausgeführt werden müssen (also so oft wiederholt werden wie es Schleifen-Durchläufe gibt).
- Nach der Schleife stehen Anweisungen, die sich wieder auf die Gesamtheit der Schleifen-Durchläufe beziehen, also etwa die Weiterverarbeitung von Variablen, die sich auf die Gesamtheit der Schleifen beziehen.
Einige Spitzfindigkeiten
Die geschweiften Klammern
In der Dokumentation wird die for-Schleife erklärt durch:
for(var in seq) expr
Im Beispiel oben lautete die Schleife (hier wird idx nicht ausdrücklich definiert):
for(i in (1:100)){
summe <- summe + i
}
Es stellen sich sofort zwei Fragen:
- Wann muss man die geschweiften Klammern setzen und wann kann man sie weglassen?
- Kann man den Schleifenkörper in die Zeile mit for schreiben oder muss man eine neue Zeile beginnen?
Zunächst zur Bedeutung der geschweiften Klammern: Die Anweisungen innerhalb der geschweiften Klammern bilden einen Block, der insgesamt den Schleifenkörper ausmacht. Besteht der Schleifenkörper aus mehreren Anweisungen, so müssen geschweifte Klammern gesetzt werden.
Besteht dagegen der Schleifenkörper nur aus einer einzigen Anweisung, so kann man die geschweiften Klammern weglassen. Es gibt jetzt zwei Möglichkeiten:
- Der Schleifenkörper steht in der Zeile mit for.
- Der Schleifenkörper steht in einer eigenen Zeile.
Die folgenden Skripte zeigen diese zwei Möglichkeiten:
summe <- 0
for(i in (1:100))
summe <- summe + i
cat("Summe: ", summe, "\n")
# Summe: 5050
summe <- 0
for(i in (1:100)) summe <- summe + i
cat("Summe: ", summe, "\n")
# Summe: 5050
Die beiden Skripte sind identisch.
Setzt man keine geschweiften Klammern für den Schleifenkörper, dann wird der Befehl, der nach der for-Anweisung kommt, – und nur dieser Befehl – als der Schleifenkörper interpretiert; im Beispiel ist dies jeweils der Befehl summe <- summe + i
. Der nächste Befehl ist bereits der Befehl nach der Schleife.
Empfohlen wird aber die Schreibweise, die selbst für einen einzigen Befehl im Schleifenkörper geschweifte Klammern verwendet. Die Gründe dafür sind einfach:
- Der Schleifenkörper ist kar als solcher zu erkennen und von den Befehlen nach der Schleife zu unterscheiden.
- Sollen später Befehle im Schleifenkörper ergänzt werden, muss man nicht umständlich Klammern hinzufügen (gerade zum Testen muss man oft Ausgaben in den Schleifenkörper einbauen).
Die Unveränderlichkeit des Vektors, über den iteriert wird
In den bisherigen Beispielen wurde meist vor der Schleife ein Vektor idx definiert, über den in der Schleife iteriert wird. Man kann hier natürlich auf die Idee kommen, diesen Vektor idx in der Schleife zu verändern. Lässt sich dadurch das Verhalten der Schleife, die ja eigentlich durch for(i in idx)
kontrolliert wird, nachträglich anpassen? Die Antwort ist nein und wird durch das folgende Beispiel bestätigt:
idx <- (1:100)
summe <- 0
for(i in idx){
summe <- summe + i
if(i > 50){
idx <- append(idx, i)
}
}
cat("Summe: ", summe, "\n")
Summe: 5050
length(idx)
# [1] 150
sum(idx)
# [1] 8825
Zeile 1, 2, 4 und 5: Dies sind die bekannten Anweisungen zur Berechnung der Summe der Zahlen von 1 bis 100.
Zeile 6 bis 8: Neu ist die if-Anweisung, in der für i = 51, 52, ..., 100 der Vektor idx um die entsprechende Zahl erweitert wird.
Wenn der veränderte Vektor in der Iteration verwendet wird, ergibt sich eine Endlos-Schleife, da immer wieder die Zahlen 51, 52, ..., 100 an idx angehängt werden. Die Ausgaben zeigen aber Folgendes:
- Der Vektor, über den iteriert wird, ist das Objekt idx so wie es definiert wurde als es in
for(i in idx)
an die Schleife übergeben wurde. Eine nachträgliche Änderung ist für den Ablauf der Schleife unerheblich. - Das Objekt idx wird in der Schleife tatsächlich verändert: man erkennt an den Ausgaben, dass die Zahlen 51, 52, ..., 100 einmal an den ursprünglichen Vektor idx angehängt wurden.
Iterierbare Objekte
Andere Vektoren als (1:n)
Bisher wurde in allen Beispielen über den Vektor (1:100)
iteriert. Dies könnte den Eindruck erwecken, dass nur Vektoren dieser Art als Wertemenge für die Zählvariable zulässig sind. Die Dokumentation ist dagegen so zu verstehen, dass ein beliebiger Vektor eingesetzt werden kann. Im folgenden Beispiel wird der Vektor gewählt, der aus den ungeraden Zahlen 1, 3, 5, ..., 99 besteht, und über diesen iteriert:
idx <- seq(from = 1, to = 99, by = 2)
summe <- 0
for(i in idx){
summe <- summe + i
}
cat("Summe: ", summe, "\n")
# Summe: 2500
# Zur Kontrolle:
sum(idx)
# [1] 2500
Die Abarbeitung der Schleife kann man sich so vorstellen:
- Die Zählvariable, hier i, nimmt beim ersten Iterationsschritt den Wert der ersten Komponente von idx an,
- beim zweiten Iterationsschritt ist i gleich der zweiten Komponente von idx und so weiter.
- Beim letzten Iterationsschritt stimmt i mit der letzten Komponente von idx überein, also ist
i == 99
. - Jetzt besitzt idx keine weitere Komponente und daher wird die Schleife verlassen und der cat()-Befehl ausgeführt (Zeile 9).
Damt sollte klar sein, dass man anstelle von idx jeden beliebigen Vektor einsetzen kann. Der Vektor muss auch nicht aus ganzen Zahlen bestehten wie das folgende Beispiel zeigt:
for(i in c(TRUE, FALSE, TRUE)){
cat("i: ", i, "\n")
}
# i: TRUE
# i: FALSE
# i: TRUE
Andere Objekte als Vektoren
Zur Iteration können nicht nur Vektoren eingesetzt werden, sondern jedes Objekt, das in einen Vektor verwandelt werden kann, zum Beispiel:
- Spalten eines Dataframes,
- Spalten oder Zeilen einer Matrix,
- Komponenten einer Liste,
- eine Liste, wobei man bei der Verarbeitung der Komponenten im Schleifenkörper darauf achten muss, dass die Komponenten unterschiedliche Datentypen haben können.
Das folgende Beispiel definiert zunächst eine Liste und iteriert in der for-Schleife über ihre Komponenten:
book <- list(author = "R-Expert", title = "Introduction to R", year = 2019)
for(i in book){
cat("i: ", i, "||", storage.mode(i), "\n")
storage.mode(i)
}
# i: R-Expert || character
# i: Introduction to R || character
# i: 2019 || double
Selbst eine Matrix kann verwendet werden, da eine Matrix intern als Vektor gespeichert wird. Iteration über eine Matrix bedeutet dann, dass der zugrunde liegende Vektor verwendet wird. Man muss dabei eventuell beachten, in welcher Reihenfolge der Vektor die Matrix-Elemente liefert.
Das folgende Skript zeigt ein einfaches Beispiel, bei dem ene Matrix definiert wird und anschließend wird die Summe der Komponenten bestimmt; an der Ausgabe erkennt man, in welcher Reihenfolge die Komponenten angearbeitet werden:
v <- (1:6)
m <- matrix(data = v, nrow = 2, byrow = TRUE)
m
# [,1] [,2] [,3]
# [1,] 1 2 3
# [2,] 4 5 6
summe <- 0
for(i in m){
cat("i: ", i, "\n")
summe <- summe + i
}
# i: 1
# i: 4
# i: 2
# i: 5
# i: 3
# i: 6
cat("Summe: ", summe, "\n")
# Summe: 21
Nicht ganz klar ist, wie sich Faktoren verhalten, wenn über sie iteriert wird. Denn Faktoren aus character-Vektoren werden intern als integer-Vektoren abgespeichert.
sample <- c("A", "A", "E", "C", "B", "A", "E", "C", "A")
length(sample) # 9
sample
# [1] "A" "A" "E" "C" "B" "A" "E" "C" "A"
mode(sample) # [1] "character"
sf <- factor(x = sample)
sf
# [1] A A E C B A E C A
# Levels: A B C E
for(i in sample){
cat("i: ", i, "\n")
}
# i: A
# i: A
# i: E
# i: C
# i: B
# i: A
# i: E
# i: C
# i: A
for(i in sf){
cat("i: ", i, "||", storage.mode(i), "\n")
}
# i: A || character
# i: A || character
# i: E || character
# i: C || character
# i: B || character
# i: A || character
# i: E || character
# i: C || character
# i: A || character
Zeile 1 bis 13: Es wird ein character-Vektor sample definiert und untersucht. Aus dem Vektor wird ein Faktor sf erzeugt und ausgegeben.
Zeile 15 bis 26: Wird über den character-Vektor sample iteriert, erkennt man in den Ausgaben die Zeichen, die in den Komponenten von sample abgespeichert sind.
Zeile 28 bis 40: Wird über den Faktor sf iteriert, so sind die Komponenten ebenfalls Zeichen; man erkennt dies ausdrücklich an der Ausgabe von storage.mode(i)
.
Die Schlüsselwörter break und next
So wie die Schleifen bisher behandelt wurden, kann man sie noch nicht sehr flexibel einsetzen: Allein der in for(i in seq)
definierte Vektor seq bestimmt den Ablauf der Schleife:
- Die Zählvariable i nimmt nacheinander die Werte der Komponenten von seq an.
- Für jeden Wert von i wird der gesamte Schleifenkörper abgearbeitet.
- Nach der letzten Komponente von seq wird die Schleife verlassen.
Manchmal ist es aber wünschenswert, dass
- unter gewissen Umständen, die Schleife vorzeitig verlassen wird oder dass
- nur ein Teil des Schleifenkörpers abgearbeitet wird (und sofort der nächste Durchlauf startet).
Diese beiden Möglichkeiten werden durch die Schlüsselwörter break und next realisiert:
- break sorgt dafür, dass die Schleife vorzeitig verlassen wird.
- next sorgt dafür, dass der folgende Teil des Schleifenkörpers übersprungen wird und die Zählvariable sofort den nächsten Wert annimmt.
Es folgen zwei Beispiele, die den Einsatz von break und next demonstrieren.
1. Beispiel: Der Einsatz von break
Es sollen wieder die Zahlen von 1 bis 100 addiert werden, aber die Berechnung soll vorzeitig abbrechen, wenn die Summe größer als 1000 ist. In diesem Fall sollen der aktuelle Wert der Zählvariable und die Summe ausgegeben werden.
Das folgende Skript zeigt eine mögliche Realisierung:
idx <- (1:100)
summe <- 0
for(i in idx){
summe <- summe + i
if(summe > 1000){
cat("Index: ", i, " || Summe: ", summe, "\n")
break
}
}
# Index: 45 || Summe: 1035
cat("Summe: ", summe, "\n")
# Summe: 1035
# Kontrolle:
sum(1:45)
# [1] 1035
Zeile 6 bis 9: Innerhalb des Schleifenkörpers wird abgefragt, ob der aktuelle Wert von summe 1000 überschreitet. Falls ja, werden der aktuelle Wert der Zählvariable und der Summe ausgegeben. Anschließend sorgt in Zeile 8 der Befehl break
dafür, dass die Schleife verlassen wird.
Zeile 12: Die Ausgabe aus der cat()-Anweisung im if-Zweig.
Zeile 14 und 15: Die Ausgabe von summe nach der Schleife zeigt, dass die Schleife tatsächlich abgebrochen wurde.
Zeile 18 und 19: Zur Kontrolle wird die Summe der Zahlen von 1 bis 45 berechnet.
2. Beispiel: Der Einsatz von next
Es sollen wieder die Zahlen von 1 bis 100 addiert werden, aber Zahlen, die durch 7 teilbar sind, sollen nicht eingerechnet werden.
Das folgende Skript zeigt eine mögliche Realisierung:
idx <- (1:100)
summe <- 0
for(i in idx){
if(i %% 7 == 0){
next
}
summe <- summe + i
}
cat("Summe: ", summe, "\n")
# Summe: 4315
# Kontrolle
5050 - sum(7*(1:14))
# [1] 4315
Zeile 5 bis 7: Falls i durch 7 teilbar ist, wird next aufgerufen und dadurch der nächste Iterationsschritt angestoßen; der Befehl summe <- summe + i
wird für durch 7 teilbare i nicht ausgeführt.
Zeile 11 bis 7: Die Summe ergibt jetzt nur noch 4315. Zur Kontrolle wird von 5050 die Summe der durch 7 teilbaren Zahlen (also 7, 14, ..., 98) abgezogen.
Verschachtelte Schleifen
Oben wurde erklärt, dass der Schleifenkörper in geschweifte Klammern eingeschlossen werden soll (falls er nur aus einer einzigen Anweisung besteht, könnte man die Klammern weglassen). Da man den Schleifenkörper mit beliebigen Anweisungen füllen kann, ist es möglich dort wiederum eine Schleife einzubauen; man spricht dann von verschachtelten Schleifen.
Eine typische Anwendung dafür ist, dass man die Werte der Komponenten einer Matrix durch zwei Iterationen setzt:
- die äußere Iteration durchläuft die Zeilen-Indizes,
- die innere Iteration durchläuft die Spalten-Indizes.
Im Kapitel Matrizen in R: der Datentyp matrix wurde gezeigt, wie man spezielle Matrizen erzeugen kann. Manchmal ist es einfacher, die Werte der Komponenten einzeln zu berechnen; das folgende Beispiel zeigt, wie man dies mit zwei Schleifen erledigen kann:
v <- (1:6)
S2 <- matrix(data = 0, nrow = 6, ncol = 6)
for(i in v){ # i: Zeilenindex
for(j in v){ # j: Spaltenindex
S2[i, j] <- i + j
}
}
S2
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] 2 3 4 5 6 7
# [2,] 3 4 5 6 7 8
# [3,] 4 5 6 7 8 9
# [4,] 5 6 7 8 9 10
# [5,] 6 7 8 9 10 11
# [6,] 7 8 9 10 11 12
outer(X = v, Y = v, FUN = "+")
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] 2 3 4 5 6 7
# [2,] 3 4 5 6 7 8
# [3,] 4 5 6 7 8 9
# [4,] 5 6 7 8 9 10
# [5,] 6 7 8 9 10 11
# [6,] 7 8 9 10 11 12
In diesem Beispiel wird die Augensumme beim zweimaligen Würfeln berechnet. Dazu wird der Vektor v der möglichen Ergebnisse bei einem Wurf vorbereitet (Zeile 1) sowie eine Matrix S2 mit geeigneten Dimensionen (Zeile 2).
In den verschachtelten Schleifen (Zeile 4 bis 8) werden die Komponenten durch die Summe von Zeilen- und Spalten-Index gesetzt. Dabei ist i der Zeilen-Index und j der Spalten-Index.
Die Ausgabe von S2 zeigt die Matrix der Augensummen (Zeile 10 bis 17). Man kann diese Matrix auch einfacher mit Hilfe der Funktion outer() erzeugen (Zeile 19).
Zusammenfassung
Bei einer for-Schleife durchläuft die Zählvariable var die Werte der Komponenten des Vektors seq. Für jede dieser Komponenten wird die Anweisung expr ausgeführt, die üblicherweise von var abhängig ist.
for(var in seq) expr
Weitere Informationen über for-Schleifen findet man in der Dokumentation unter ?Control
im Paket base.