Zweidimensionale Arrays
Kurz gesagt: Ein zweidimensionales Array (Matrix) ist in Python eine Liste von Listen: Jedes Element der äußeren Liste ist eine Zeile, und verschachtelte Schleifen gehen durch alle Werte.
Problem
Drei Wochen, drei Listen
Ein Café notiert, wie viele Kaffees es an jedem Werktag verkauft hat. Für eine Woche ist die Liste aus der letzten Lektion genau das Richtige. Für drei Wochen legst du drei Listen an:
week1 = [42, 38, 51, 47, 60]week2 = [45, 40, 49, 52, 63]week3 = [39, 44, 50, 48, 58]
tuesday = week1[1] + week2[1] + week3[1]print(f"Dienstag: {tuesday}")Dienstag: 122Jetzt fragt die Chefin, wie viel an allen Dienstagen des letzten Jahres verkauft wurde. Das sind 52 Wochen, also 52 Listen 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 eine Liste, die eine Tabelle ist.
Die Idee
Eine Liste von Listen: Zeile und Spalte
Eine Tabelle ist in Python eine Liste von Listen: Jedes Element der äußeren Liste ist eine ganze Zeile, und eine Zeile ist eine gewöhnliche Liste mit Zahlen. In Java und C# heißt das zweidimensionales Array, oft auch Matrix.
sales = [ [42, 38, 51, 47, 60], [45, 40, 49, 52, 63], [39, 44, 50, 48, 58],]print(sales[1][0])print(f"{len(sales)} Wochen, {len(sales[0])} 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.len(sales)ist die Anzahl der Zeilen.len(sales[0])ist die Länge der ersten Zeile, also die Anzahl der Spalten.
sales[1] ist eine ganze Zeile, eine gewöhnliche Liste mit 5 Zahlen. Deshalb schreibst du zwei getrennte Klammern [1][0]: Zuerst holst du die Zeile, dann die Zahl darin.
sales = [ [42, 38, 51, 47, 60], [45, 40, 49, 52, 63], [39, 44, 50, 48, 58],]print(sales[1])print(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.
table = []for week in range(52): table.append([0] * 5)table[0][1] = 7print(len(table), len(table[0]), table[0][1], table[1][1])52 5 7 0Genauer, für Neugierige
- Da die Zeilen eigene Listen sind, können sie unterschiedlich lang sein. So eine Tabelle heißt verzweigt (jagged):
shifts = [ [8, 8], [6, 6, 6], [12],]print(len(shifts[1]), len(shifts[2]))3 1In ihr ist len(sales[0]) nicht die Länge jeder Zeile. Deshalb ist es in einer verschachtelten Schleife sicherer, len(sales[row]) zu schreiben: die Länge der Zeile, durch die du gerade gehst.
- Bau die leere Tabelle nicht mit
[[0] * 5] * 3. Dann zeigen alle drei Plätze auf ein und dieselbe Zeile, wie die zwei Namen einer Liste aus der letzten Lektion. Eine Änderung in einer Zeile sieht man in allen:
table = [[0] * 5] * 3table[0][1] = 7print(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 week in range(len(sales)): for day in range(len(sales[0])): print(f"{sales[week][day]:5}", end="") print() 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.
:5 im f-String gibt die Zahl in einem Feld von 5 Zeichen aus, rechtsbündig. So stehen die Spalten genau untereinander. end="" hält die Zahlen in einer Zeile, und das leere print() nach jeder Zeile wechselt in eine neue.
Probier es aus
Welche Zelle?
Im Notenbuch ist jede Zeile ein Schüler und jede Spalte ein Fach.
Was gibt das Programm aus?
grades = [ [5, 3, 4, 6], [3, 4, 6, 5], [6, 2, 5, 4],]print(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 week in range(len(sales)): total = 0 for day in range(len(sales[0])): total += sales[week][day] print(f"Woche {week + 1}: {total}")Woche 1: 238Woche 2: 249Woche 3: 239sales = [ [42, 38, 51, 47, 60], [45, 40, 49, 52, 63], [39, 44, 50, 48, 58],]for week in range(len(sales)): total = 0 for day in range(len(sales[0])): total += sales[week][day] print(f"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?
days = ["Mo", "Di", "Mi", "Do", "Fr"]
for day in range(len(sales[0])):
total = 0
for week in range(len(sales)):
total += sales[][day]
print(f"{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 len(hall[0]) (5). len(hall) ist die Anzahl der Reihen (3), deshalb werden die letzten zwei Plätze jeder Reihe nie geprüft. Python 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 die Liste ist sie die Reihe 0. Deshalb ziehst du von den Zahlen, die ein Mensch eingibt, 1 ab, bevor du sie als Indizes verwendest:
row = int(input())seat = int(input())if hall[row - 1][seat - 1] == 1: print("Der Platz ist belegt.")else: hall[row - 1][seat - 1] = 1 print(f"Gebucht: Reihe {row}, Platz {seat}")32Gebucht: Reihe 3, Platz 212Der Platz ist belegt.hall ist der Saal von der vorigen Karte. Eine Zelle änderst du wie eine gewöhnliche Variable: hall[row - 1][seat - 1] = 1.
Genauer, für Neugierige
- Wenn jemand Reihe 7 will, liegt Index 6 außerhalb der Tabelle, und das Programm bricht mit
IndexErrorab, genau wie bei einer gewöhnlichen Liste. Tückischer ist Reihe 0: Der Index ist -1, und das ist in Python die letzte Reihe. Es gibt keinen Fehler, und der falsche Platz wird gebucht:
hall = [ [1, 1, 0, 0, 1], [0, 1, 1, 1, 0], [0, 0, 0, 1, 1],]try: print(hall[7 - 1][2 - 1])except IndexError as error: print(f"IndexError: {error}")print(hall[0 - 1])IndexError: list index out of range[0, 0, 0, 1, 1]Prüf deshalb die Zahlen, bevor du sie verwendest: 1 <= row <= len(hall), 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 Listen: dr = [-1, 1, 0, 0] und 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 · Listen
- Geht weiter in: Parameter und return · OOP-Prinzipien · Entwurfsmuster · Graph: Adjazenzliste und Matrix
- Aufgaben zum Thema: Sprachgrundlagen