Zweidimensionale Arrays
Kurz gesagt: Ein zweidimensionales Array (Matrix) ist in JavaScript ein Array von Arrays: Jedes Element des äußeren Arrays ist eine Zeile, und verschachtelte Schleifen gehen durch alle Werte.
Problem
Drei Wochen, drei Arrays
Ein Café notiert, wie viele Kaffees es an jedem Werktag verkauft hat. Für eine Woche ist das Array aus der letzten Lektion genau das Richtige. Für drei Wochen legst du drei Arrays an:
const week1 = [42, 38, 51, 47, 60];const week2 = [45, 40, 49, 52, 63];const week3 = [39, 44, 50, 48, 58];
const tuesday = week1[1] + week2[1] + week3[1];console.log(`Dienstag: ${tuesday}`);Dienstag: 122Jetzt fragt die Chefin, wie viel an allen Dienstagen des letzten Jahres verkauft wurde. Das sind 52 Wochen, also 52 Arrays und eine Summe mit 52 Summanden. Und eine Schleife kann nicht durch week1, week2, week3 gehen: Das sind verschiedene Namen, keine Indizes.
Die Daten sind eine Tabelle: Die Wochen sind Zeilen, die Tage sind Spalten. Du brauchst ein Array, das eine Tabelle ist.
Die Idee
Ein Array von Arrays: Zeile und Spalte
Eine Tabelle ist in JavaScript ein Array von Arrays: Jedes Element des äußeren Arrays ist eine ganze Zeile, und eine Zeile ist ein gewöhnliches Array mit Zahlen. So ein Array heißt zweidimensional, oft auch Matrix.
const sales = [ [42, 38, 51, 47, 60], [45, 40, 49, 52, 63], [39, 44, 50, 48, 58],];console.log(sales[1][0]);console.log(`${sales.length} Wochen, ${sales[0].length} Tage`);453 Wochen, 5 Tage- Jedes innere
[ … ]ist eine Zeile. Wir schreiben sie untereinander, damit man die Tabelle sieht. sales[1][0]ist die Zeile mit Index 1 (die zweite Woche) und die Spalte mit Index 0 (Montag). Zuerst kommt die Zeile, dann die Spalte. Auch hier zählt man ab 0.sales.lengthist die Anzahl der Zeilen.sales[0].lengthist die Länge der ersten Zeile, also die Anzahl der Spalten.
sales[1] ist eine ganze Zeile, ein gewöhnliches Array mit 5 Zahlen. Deshalb schreibst du zwei getrennte Klammern [1][0]: Zuerst holst du die Zeile, dann die Zahl darin.
const sales = [ [42, 38, 51, 47, 60], [45, 40, 49, 52, 63], [39, 44, 50, 48, 58],];console.log(sales[1]);console.log(sales);[ 45, 40, 49, 52, 63 ][ [ 42, 38, 51, 47, 60 ], [ 45, 40, 49, 52, 63 ], [ 39, 44, 50, 48, 58 ]]Eine leere Tabelle 52 × 5 voller Nullen baust du Zeile für Zeile: 52-mal fügst du eine neue Zeile aus 5 Nullen hinzu.
const table = [];for (let week = 0; week < 52; week++) { table.push(new Array(5).fill(0));}table[0][1] = 7;console.log(table.length, table[0].length, table[0][1], table[1][1]);52 5 7 0Genauer, für Neugierige
- Da die Zeilen eigene Arrays sind, können sie unterschiedlich lang sein. So eine Tabelle heißt verzweigt (jagged):
const shifts = [ [8, 8], [6, 6, 6], [12],];console.log(shifts[1].length, shifts[2].length);3 1In ihr ist sales[0].length nicht die Länge jeder Zeile. Deshalb ist es in einer verschachtelten Schleife sicherer, sales[row].length zu schreiben: die Länge der Zeile, durch die du gerade gehst.
- Bau die leere Tabelle nicht mit
new Array(3).fill(new Array(5).fill(0)). Dann zeigen alle drei Plätze auf ein und dieselbe Zeile, wie die zwei Namen eines Arrays aus der letzten Lektion. Eine Änderung in einer Zeile sieht man in allen:
const table = new Array(3).fill(new Array(5).fill(0));table[0][1] = 7;console.log(table);[ [ 0, 7, 0, 0, 0 ], [ 0, 7, 0, 0, 0 ], [ 0, 7, 0, 0, 0 ] ]Sieh es dir an
Die ganze Tabelle auf dem Bildschirm
Um durch jede Zelle zu gehen, brauchst du zwei Schleifen, eine in der anderen. Verschachtelte Schleifen kennst du schon von den Sternchen: Die äußere wählt die Zeile, die innere geht durch die Spalten dieser Zeile.
for (let week = 0; week < sales.length; week++) { let line = ""; for (let day = 0; day < sales[0].length; day++) { line += String(sales[week][day]).padStart(5); } console.log(line);} 42 38 51 47 60 45 40 49 52 63 39 44 50 48 58Die äußere Schleife läuft 3-mal, einmal für jede Woche. In jeder ihrer Runden läuft die innere 5-mal. Insgesamt 15 Zellen, in der Reihenfolge, in der du eine Tabelle liest: von links nach rechts, von oben nach unten.
String(x).padStart(5) macht aus der Zahl einen Text und füllt ihn links mit Leerzeichen auf 5 Zeichen auf. So stehen die Spalten genau untereinander. Die Zeile wird in line gesammelt, und console.log(line) gibt sie nach der inneren Schleife aus.
Probier es aus
Welche Zelle?
Im Notenbuch ist jede Zeile ein Schüler und jede Spalte ein Fach.
Was gibt das Programm aus?
const grades = [ [5, 3, 4, 6], [3, 4, 6, 5], [6, 2, 5, 4],];console.log(grades[1][2]);Der erste Index ist die Zeile: 1 ist der zweite Schüler, [3, 4, 6, 5]. Der zweite Index ist die Spalte: 2 ist das dritte Fach. Die Note ist 6. Die 2 kommt heraus, wenn du Zeile und Spalte vertauschst, und die 3, wenn du ab 1 zählst.
Die Idee
Summen pro Zeile und pro Spalte
Wie viele Kaffees wurden in jeder Woche verkauft? Das ist die Summe jeder Zeile. Die Summe beginnt für jede neue Zeile bei 0, deshalb steht total innerhalb der äußeren Schleife:
for (let week = 0; week < sales.length; week++) { let total = 0; for (let day = 0; day < sales[0].length; day++) { total += sales[week][day]; } console.log(`Woche ${week + 1}: ${total}`);}Woche 1: 238Woche 2: 249Woche 3: 239const sales = [ [42, 38, 51, 47, 60], [45, 40, 49, 52, 63], [39, 44, 50, 48, 58],];for (let week = 0; week < sales.length; week++) { let total = 0; for (let day = 0; day < sales[0].length; day++) { total += sales[week][day]; } console.log(`Woche ${week + 1}: ${total}`);}Schritt für Schritt, in Worten
- Die Tabelle: 3 Wochen (Zeilen) mit je 5 Tagen (Spalten).
- week = 0: total beginnt wieder bei 0.
- Die innere Schleife geht durch die Tage: 42 + 38 + 51 + 47 + 60 = 238.
- Sie gibt „Woche 1: 238“ aus.
- week = 1: total beginnt wieder bei 0.
- Die innere Schleife geht durch die Tage: 45 + 40 + 49 + 52 + 63 = 249.
- Sie gibt „Woche 2: 249“ aus.
- week = 2: total beginnt wieder bei 0.
- Die innere Schleife geht durch die Tage: 39 + 44 + 50 + 48 + 58 = 239.
- Sie gibt „Woche 3: 239“ aus.
Wie viel wurde am Montag verkauft, am Dienstag und so weiter? Das ist die Summe jeder Spalte. Die Tabelle bleibt dieselbe, nur die Reihenfolge der Schleifen ändert sich: Außen steht der Tag, innen stehen die Wochen. Du schreibst es auf der nächsten Karte fertig.
Welche Schleife außen steht, entscheidet, was du addierst. Die Indizes in sales[week][day] wandern nicht: Zuerst kommt immer die Zeile.
Probier es aus
Summe pro Tag
Die äußere Schleife geht durch die Tage, die innere durch die Wochen. Was gehört in die Lücke?
const days = ["Mo", "Di", "Mi", "Do", "Fr"];
for (let day = 0; day < sales[0].length; day++) {
let total = 0;
for (let week = 0; week < sales.length; week++) {
total += sales[][day];
}
console.log(`${days[day]}: ${total}`);
}week. Die Zeile ist die Woche, deshalb steht week an erster Stelle. Der Tag bleibt stehen, während die innere Schleife durch die drei Wochen geht. Für Dienstag kommt 38 + 40 + 44 = 122 heraus, dasselbe wie auf der ersten Karte, aber ohne 52 Namen.
Probier es aus
Finde den Fehler
Der Saal hat 3 Reihen mit je 5 Plätzen: 1 ist belegt, 0 ist frei. Es gibt 7 freie Plätze, aber das Programm sagt 5. In welcher Zeile steckt der Fehler?
Wähle die Zeile mit dem Fehler.
Die innere Schleife ist für die Plätze in der Reihe, und ihre Anzahl ist hall[0].length (5). hall.length ist die Anzahl der Reihen (3), deshalb werden die letzten zwei Plätze jeder Reihe nie geprüft. JavaScript sieht so einen Fehler nicht: Beides sind Zahlen, und das Programm läuft.
Die Idee
Reservierung: Menschen zählen ab 1
Ein Kinobesucher will Reihe 3, Platz 2. Für ihn ist die erste Reihe die Reihe 1. Für das Array ist sie die Reihe 0. Deshalb ziehst du von den Zahlen, die ein Mensch eingibt, 1 ab, bevor du sie als Indizes verwendest:
const row = Number(await ask(""));const seat = Number(await ask(""));if (hall[row - 1][seat - 1] === 1) { console.log("Der Platz ist belegt.");} else { hall[row - 1][seat - 1] = 1; console.log(`Gebucht: Reihe ${row}, Platz ${seat}`);}32Gebucht: Reihe 3, Platz 212Der Platz ist belegt.hall ist der Saal von der vorigen Karte, und die Zeilen für ask() und rl.close() sind wie in der Lektion „Eingabe und Ausgabe“. Eine Zelle änderst du wie eine gewöhnliche Variable: hall[row - 1][seat - 1] = 1;.
Genauer, für Neugierige
- Wenn jemand Reihe 7 will, ist
hall[6]gleichundefined, undundefined[1]bricht das Programm mitTypeErrorab. Will jemand Platz 10 in einer Reihe, die es gibt, kommt kein Fehler:hall[2][9]istundefined, und die Zuweisung hängt einen neuen Platz ans Ende der Reihe. Die Reihe hat jetzt 10 Plätze:
const hall = [ [1, 1, 0, 0, 1], [0, 1, 1, 1, 0], [0, 0, 0, 1, 1],];try { console.log(hall[7 - 1][2 - 1]);} catch (error) { console.log(`${error.name}: ${error.message}`);}hall[3 - 1][10 - 1] = 1;console.log(hall[2].length);TypeError: Cannot read properties of undefined (reading '1')10Prüf deshalb die Zahlen, bevor du sie verwendest: row >= 1 && row <= hall.length, und dasselbe für den Platz.
- Hier steht jede Zahl in einer eigenen Zeile. Wie du eine ganze Zeile mit Zahlen auf einmal liest (
0 1 1 0), siehst du in der nächsten Lektion über Text.
Übung
Rechnen mit einer Tabelle
Löse die Aufgaben in deinem Editor. Schreib die Tabellen direkt in den Code.
1. Diagonalen und Zeilen. Finde für die Tabelle 2 × 2 unten die Summe der Hauptdiagonale (von oben links nach unten rechts), die Summe der anderen Diagonale und die Summen der ersten und der zweiten Zeile. Auf der Hauptdiagonale sind der Index der Zeile und der Index der Spalte gleich. Auf der anderen Diagonale ist die Spalte n - 1 - row.
1 23 4Hauptdiagonale: 5Nebendiagonale: 5Erste Zeile: 3Zweite Zeile: 72. Dreh die Tabelle um. Die Verkäufe sind nach Wochen (Zeilen) und Tagen (Spalten) notiert. Die Buchhaltung will sie nach Tagen und Wochen. Erzeuge eine neue Tabelle, in der die Zeilen zu Spalten werden. Das nennt man Transponieren. Die neue Tabelle hat die Maße Spalten × Zeilen, und die Zelle [r][c] wandert nach [c][r].
42 38 51 45 40 49 42 45 38 40 51 49Übung
Labyrinthe und ein Schatz
3. Wie viele Wege gibt es? Das Labyrinth ist eine Tabelle: 0 ist ein Durchgang, 1 ist eine Wand. Du startest in der oberen linken Ecke und kommst zur unteren rechten, wobei du dich nur nach rechts oder nach unten bewegst. Wie viele verschiedene Wege gibt es?
0 0 0 00 1 0 00 0 0 11 0 0 0Wege: 3Tipp
Leg eine zweite Tabelle ways mit derselben Größe an. Schreib hinein, auf wie viele Arten man jede Zelle erreicht. Den Start erreicht man auf 1 Art. Eine Wand auf 0 Arten. Jede andere Zelle erreicht man entweder von oben oder von links, deshalb ist die Anzahl die Summe aus der Zelle darüber und der Zelle links davon (falls es sie gibt). Füll die Tabelle Zeile für Zeile aus, von oben nach unten. Die Antwort steht in der letzten Zelle.
4. Der kürzeste Weg. Eine schwere Aufgabe. Jetzt darfst du dich in alle vier Richtungen bewegen: nach oben, nach unten, nach links und nach rechts. Mit wie vielen Schritten kommst du mindestens von der oberen linken zur unteren rechten Ecke? Gibt es keinen Weg, gib „Kein Weg“ aus.
0 0 0 0 01 1 1 1 00 0 0 0 00 1 1 1 10 0 0 0 0Kürzester Weg: 16 SchritteTipp
Schick eine „Welle“ vom Start los. Leg eine Tabelle dist voller -1 an (diese Zelle haben wir noch nicht erreicht) und setz 0 an den Start. Dann wiederhole: Finde alle Zellen, deren dist gleich dem aktuellen Schritt ist, und schreib bei ihren freien Nachbarn, die wir noch nicht erreicht haben, Schritt + 1 hinein. Die Welle wächst in jeder Runde um einen Schritt. Hör auf, wenn sie das Ziel erreicht oder wenn sich nichts mehr geändert hat (dann gibt es keinen Weg). Die vier Richtungen sind praktisch als zwei Arrays: const dr = [-1, 1, 0, 0]; und const dc = [0, 0, -1, 1];. Der Nachbar in Richtung k liegt in Zeile r + dr[k] und Spalte c + dc[k].
Weitere Aufgaben
- Finde den Schatz. Ein Spiel auf einer Karte, die eine Tabelle ist: 0 ist ein Weg, 1 ist ein Hindernis, 2 ist der Schatz. Der Spieler startet in der oberen linken Ecke. Gib bei jedem Zug die Karte aus (
Pfür den Spieler,#für ein Hindernis,.für einen Weg) und lies einen Befehl als Zahl ein: 8 nach oben, 2 nach unten, 4 nach links, 6 nach rechts (wie auf dem Ziffernblock). Führt der Zug aus der Karte hinaus oder in ein Hindernis, bleibt der Spieler stehen. Wenn er auf den Schatz tritt, gib „Du hast den Schatz in … Zügen gefunden!“ aus. - Die Woche mit den meisten Verkäufen. Finde für die Tabelle
salesheraus, welche Woche die stärkste war und welcher Wochentag im Durchschnitt der stärkste ist. - Freie Plätze nebeneinander. Finde für den Saal
halleine Reihe, in der mindestens 3 freie Plätze nebeneinander liegen, und gib die Nummer der Reihe und des ersten Platzes aus.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Operatoren und Arithmetik · Bedingungen · Schleifen · Arrays
- Geht weiter in: Parameter und return · OOP-Prinzipien · Entwurfsmuster · Graph: Adjazenzliste und Matrix
- Aufgaben zum Thema: Sprachgrundlagen