Programmierkurs
für Naturwissenschaftler/innen

Iteration

In diesem Abschnitt geht es um Wiederholungen.

for-Schleifen

Eine Methode, um etwas zu wiederholen, ist die for-Schleife.

Sie möchten nun zum Beispiel die Summe der Kuben der ganzen Zahlen zwischen 1 und 10 finden.

Theoretisch könnte Sie es als

let sum;
sum = 1 ** 3 + 2 ** 3 + 3 ** 3 + 4 ** 3 + 5 ** 3 + 6 ** 3 + 7 ** 3 + 8 ** 3 + 9 ** 3 + 10 ** 3;
console.log(sum);

schreiben, aber das ist fehleranfällig. Außerdem wird sie noch länger und fehleranfälliger, wenn man den Fall von 1 bis 100 berechnen möchte.

In solchen Fällen verwendet man eine for-Schleife wie folgt. (Mehr dazu später. Für den Moment überfliegen Sie dies einfach.)

let sum = 0;	// Vergessen Sie nicht die Initialisierung

let i;
for (i = 1; i <= 10; i++) {
  sum += i ** 3; // sum = sum + i ** 3; ist auch möglich
}
console.log(sum);

Ein entsprechendes Flussdiagramm sieht so aus.

/images/loop-for-sum.png
for-loop

Vergleichen Sie das obige Programm mit dem Flussdiagramm und sehen Sie, wo die beiden gleich sind.

Neben dem Fluss von oben nach unten ist auch ein Rückfluss zu erkennen. Das heißt, dass dies auch eine Kontrollstruktur ist. Sie können auch sehen, dass es sich im Wesentlichen um eine bedingte Verzweigung handelt, wie man am Aussehen der Raute erkennen kann.

Beginnen wir mit einem einfachen Beispiel, um Ihnen eine Vorstellung zu vermitteln.

Geben Sie das folgende Programm ein und führen Sie es aus. Die Details werden gleich erklärt, aber stellen Sie sich einfach vor, was Sie tun. (Sie können auch zuerst die Erklärung lesen und es später ausprobieren).

let i;
for (i = 0; i < 3; i++) {
  console.log(i);
}

Ergebnis

Geben Sie das folgende Programm ein und führen Sie es aus. Die Details werden gleich erklärt, aber stellen Sie sich einfach vor, was Sie tun. (Sie können auch zuerst die Erklärung lesen und es später ausprobieren).

let sum = 0;
let i;
for (i = 1; i <= 5; i++) {
  sum += i;
  console.log("  i =", i, ", sum =", sum);
}
console.log("Sum is", sum);

Ergebnis

Aufbau einer for-Schleife

Schauen wir uns die Struktur der for-Schleife anhand eines einfachen Beispiels genauer an.

let i;
for (i = 0; i < 3; i++) {
  console.log(i);
}

Die Struktur der for-Schleife ist wie folgt:

  1. die Zeichenkette for

  2. der von ( und ) eingeschlossene Teil

  3. Block (der von { und } eingeschlossene Teil)

Der Block enthält die eigentlichen Anweisungen. Dieser Teil wird wiederholt ausgeführt.

Der wichtige Teil der for-Schleife ist der in ( und ) eingeschlossene Teil. Der Teil von () besteht aus den folgenden Elementen, die jeweils durch ; getrennt werden. Diese ; können nicht weggelassen werden. In der Reihenfolge von vorne nach hinten:

  1. Initialisierung

  2. Schleifenbedingung

  3. Fortsetzung

Jeder von ihnen hat die folgende Aufgabe. Beobachten Sie insbesondere wann die einzelnen Aufgaben ausgeführt werden.

Initialisierung

  • for (i = 0; i < 3; i++) {

Dies wird ausgeführt, bevor die for-Schleife beginnt. Sie wird zuerst und nur einmal ausgeführt. Sie wird meist zur Initialisierung einer Schleifenvariable (eine temporäre Variable, die dazu dient, die Anzahl der Ausführungszyklen einer Schleife zu zählen. Auch bekannt als Schleifenzähler. In diesem Beispiel ist i die Schleifenvariable.) verwendet.

Schleifenbedingung

  • for (i = 0; i < 3; i++) {

Solange dies erfüllt ist, wird der Block wiederholt ausgeführt. Genauer gesagt, wird sie vor der Ausführung des Blocks ausgewertet, und wenn das Ergebnis wahr ist, wird der Block ausgeführt.

Fortsetzung

  • for (i = 0; i < 3; i++) {

Dies ist die Anweisung, die nach der Ausführung des Blocks ausgeführt wird. Sie wird zur Aktualisierung der Schleifenvariablen verwendet.

[Zur Information]

Initialisierung, Schleifenbedingung bzw. Fortsetzung können weggelassen werden, wenn sie nicht benötigt werden.

Es ist keine gute Art, sie zu schreiben, aber man kann sie zum Beispiel so schreiben

let i = 1
for ( ; i < 3; i++) {	// ! Möglich, aber zu vermeiden !
  console.log("Hello, World");
}

Teilzusammenfassung

Zusammengefasst hat die for-Schleife die folgende Struktur:

for ([Initialisierung]; [Schleifenbedingung]; [Fortsetzung]) {
  Anweisungen
}

Das Flussdiagramm für die for-Schleife sieht wie folgt aus:

/images/loop-for.png
for-loop

Beachten Sie, dass jede Schleife in dieser Reihenfolge wiederholt wird:

  1. Auswertung der Schleifenbedingung

  2. Ausführung des Blocks

  3. Fortsetzung

Probieren Sie das folgende Beispiel aus.

Klicken Sie unten auf Run , um das folgende Programm auszuführen. Es markiert die Teile des Programms, die gerade laufen, so dass Sie sehen können, wo und wann sie laufen.

Ergebnis

Überprüfen Sie in den nächsten beiden Übungen nochmal, wann welche Teile ausgeführt werden.

Wie oft wird Hello, World angezeigt, wenn Sie das folgende Programm ausführen? Warum ist das so? Wenn Sie die Antworten herausgefunden haben, führen Sie das Programm aus und sehen Sie, was passiert.

let i;
for (i = 0; i < -1; i++) {
  console.log("Hello, World\n");
}

Ergebnis

Was sehen Sie, wenn Sie das folgende Programm ausführen? Warum ist das so? Wenn Sie die Antworten herausgefunden haben, führen Sie das Programm aus und sehen Sie, was passiert.

let i;
for (i = 1; i <= 10; i++) {
  // Nichts tun
}
console.log(i);

Ergebnis

Wo wird die Schleifenvariable deklariert?

In den vorangegangenen Beispielen wurden die Variablendeklaration wie folgt geschrieben:

let i;
for (i = 0; i < 3; i++) {
  ...
}

// i ist auch nach dieser Zeile noch gültig.

In der Praxis wird sie oft wie folgt geschrieben:

for (let i = 0; i < 3; i++) {
  ...
}

// Hier ist i nicht mehr gültig.

So geschrieben, kann i nur innerhalb einer for-Schleife verwendet werden. Dies wird im Abschnitt Scope ausführlicher erläutert.

Letzteres ist die bevorzugte Schreibweise, da es i. d. R. besser ist, den gültigen Bereich einer Variablen so eng wie möglich zu halten.

Anfangswert der Schleifenvariablen

Um Hallo, World zehnmal auszugeben, könnten Sie zum Beispiel wie folgt vorgehen:

for (let i = 0; i < 10; i++) {
  console.log("Hello, World");
}

Sie können dies auch wie folgt schreiben:

for (let i = 1; i <= 10; i++) {
  console.log("Hello, World");
}

Man schreibt (in JavaScript und C) nicht oft auf diese Weise. Dies ist eine Konvention, aber Sie sollten sich an beide Schreibweisen gewöhnen.

Bei der Berechnung von Summen hingegen beginnt i mit 1, wie im Folgenden dargestellt:

let sum = 0;
for (let i = 1; i <= 10; i++) {
  sum += i;
}
console.log(sum);

Der Hauptunterschied zwischen den beiden Beispielen besteht darin, dass im ersten Beispiel der Wert von i im Block nicht verwendet wird (er dient nur dazu, die Anzahl der Schleifen zu zählen), während im zweiten Beispiel der Wert von i tatsächlich für die Berechnung verwendet wird.

Schreiben Sie mithilfe der for-Schleife ein Programm, die Summe der ganzen Zahlen von 1 bis 100 zu ermitteln.

Ergebnis

while-Schleife

Bei for-Schleifen ist die Anzahl der Iterationen wichtig. Andererseits gibt es Fälle, in denen die Anzahl der Iterationen nicht im Voraus bekannt ist, man aber so lange iterieren möchte, wie bestimmte Bedingungen erfüllt sind.

Zum Beispiel: Wir summieren die Kuben der ganzen Zahlen ab 1. Wir möchten nun wissen, wann die Gesamtzahl zum ersten Mal 1000 übersteigt. In diesem Fall ist die Anzahl der Iterationen nicht im Voraus bekannt, so dass es schwierig ist, dafür mit for-Schleife zu schreiben.

In diesem Fall kann man while verwenden:

let n = 0;
let sum = 0;
while (sum < 1000) {
  n++;
  sum += n ** 3;
  console.log(n, sum);
}
console.log("Result: ", n, sum);

Geben Sie das obige Programm ein und führen Sie es aus. Versuchen Sie sich vorzustellen, was jeder Teil des Programms tut.

Ergebnis

Die Struktur der while-Schleife ist wie folgt:

while ([Schleifenbedingung]) {
  Anweisungen
}
/images/loop-while.png
while-loop

Die Schleifenbedingung wird zuerst ausgewertet und wenn sie wahr ist, wird der Block ausgeführt. Da die Bedingung zuerst ausgewertet wird (wie bei for-Schleife), kann der Block nie ausgeführt werden.

Das folgende Programm addiert die Quadrate ganzer Zahlen ab 1 und findet heraus, wann sie zum ersten Mal 10 überschreiten.

  1. Klicken Sie unten auf Run , um das folgende Programm auszuführen. Es markiert die Teile des Programms, die gerade laufen, so dass Sie sehen können, wo und wann sie laufen.

  2. Zeichnen Sie ein Flussdiagramm dieses Programms.

Ergebnis

Ich sagte oben, dass es schwer ist, dies mit for-Schleife zu schreiben, aber man kann es tatsächlich in eine for-Schleife schreiben.

// ! Das ist keine gute Art zu schreiben !
let sum = 0;
for (let i = 1; sum < 1000; i++) {	// i und sum treten zur gleichen Zeit auf
  sum += i ** 3;
}
console.log(sum);

Dies ist jedoch keine gute Art, es zu schreiben. Das () von for setzt sich aus mehreren Variablen zusammen, was verwirrend ist (und bei späterer Betrachtung leicht missverstanden werden kann). In Anbetracht der (englischen) Bedeutungen von for und while ist while in diesem Fall besser geeignet.

Es ist wichtig, Programme so zu schreiben, dass sie auch für andere Leute leicht verständlich sind, denn wenn sie für andere leicht zu verstehen sind, sind sie auch für Sie leicht zu verstehen, wenn Sie sie sich die Programme später ansehen, und solche Programme haben weniger Fehler, oder wenn sie Fehler haben, sind sie leichter zu finden.

Ein Programm, das nach dem Motto Hauptsache, es funktioniert geschrieben wurde, wird wahrscheinlich Fehler enthalten.

Schreiben Sie Programme, die auch für andere leicht zu verstehen sind, auch wenn Sie nicht vorhaben, sie anderen zu zeigen.

Schauen wir uns einen der häufig auftretenden Fehler an.

  1. Geben Sie das folgende Programm ein und führen Sie es aus. Überlegen Sie, was passiert ist und warum.

    let n = 50;
    
    while (n < 0) {
        n -= 10;
        console.log("in while:", n);
    }
    
    console.log("result:", n);
  2. Angenommen, der Programmierer wollte von n wiederholt 10 abziehen und beenden, wenn n negativ wird. Überlegen Sie in diesem Fall, welcher Teil des Programms geändert werden sollte und wie. Ändern Sie sie und überprüfen Sie, ob sie wie erwartet funktioniert. (Am Ende sollte result: -10 angezeigt werden, was dem erwarteten Ergebnis entspricht.)

Ergebnis

do-while-Schleife

do-while-Schleife ist sehr ähnlich wie while. Der Unterschied ist nur, dass es mindestens einmal ausgeführt wird. Er wird relativ selten verwendet.

do {
  Anweisungen
} while ([Schleifenbedingung]);

In der do-while-Schleife wird zunächst ein Block ausgeführt. Nach der Ausführung des Blocks wird die Schleifenbedingung ausgewertet und wenn sie erfüllt ist, wird die Schleife wiederholt.

/images/loop-do-while.png
do-while-loop

Das folgende Programm dividiert $x$ durch 2, bis der Betrag von $x$ kleiner als 1 ist.

  1. Klicken Sie auf Run , um das folgende Programm auszuführen. Es markiert die Teile des Programms, die gerade laufen, so dass Sie sehen können, wo und wann sie laufen.

  2. Zeichnen Sie ein Flussdiagramm dieses Programms.

Ergebnis

break

Wenn Sie aus einer Schleife ausbrechen möchten, können Sie break verwenden. Die Verwendung von break sollte jedoch nach Möglichkeit vermieden werden. Bevor Sie ihn verwenden, sollten Sie genau überlegen, ob er wirklich notwendig ist und ob es eine bessere Möglichkeit gibt, ihn zu schreiben. break kann in for, while und do-while verwendet werden.

Ein relativ häufiges Muster ist das folgende.

Wenn Sie eine iterative Berechnung durchführen (z. B. mit der Newton-Raphson-Verfahren) und diese beenden möchten, wenn sie konvergiert, könnten Sie theoretisch wie folgt schreiben:

do {
  // Berechnung
} while (! converged);	// Sie schreiben hier die konkrete Bedingung der Konvergenz.

Wenn die Konvergenz jedoch nicht garantiert ist (was fast immer der Fall ist), ist es oft wünschenswert, eine maximale Anzahl von Iterationen festzulegen und aufzugeben, wenn die Konvergenz nicht innerhalb dieser Anzahl eintritt. In einem solchen Fall kann man zum Beispiel wie folgt schreiben:

let MAXLOOP = 100;

for (let i = 0; i < MAXLOOP; i++) {
  // Berechnung

  if (converged) {
    break;
  }
}

Oder, fast identisch, das Folgende:

let MAXLOOP = 100;

let i = 0;
do {
  // Berechnung

  if (converged) {
    break;
  }
  i++;
} while (i < MAXLOOP);

Dies kann als do-while mit einer begrenzten Anzahl der Schleifen (in diesem Fall 100) betrachtet werden.

Wenn Sie break in einer verschachtelten for/while/do-while-Schleife (einer Schleife innerhalb einer Schleife) verwenden, wird die innerste Schleife von break aus verlassen.

Anmerkung zu Schleifen

Achten Sie beim Schreiben von Schleifen sehr genau auf die Schleifenbedingung. Es ist ein häufiger Fehler, eine Schleife zu viel oder eine zu wenig zu haben. Solche Fehler sind auch oft nur schwer zu finden.

Wenn Sie eine Bedingung schreiben, die immer wahr ist (und nie falsch wird), entsteht eine Endlosschleife, die auch natürlich vermieden werden soll.

Zusammenfassung

In diesem Abschnitt haben Sie die Grundlagen der Iteration kennen gelernt. Für die Wiederholung können

  • for

  • while

  • do-while

verwendet werden. Sie haben auch break kennengelernt, der verwendet wird, eine Schleife zu unterbrechen.