1. Worin unterscheiden sich gezackte Arrays von zweidimensionalen?
Jetzt sind wir bei einem Thema angekommen, das viele „Arrays von Arrays“ oder „gezackte Arrays“ nennen – auf Englisch jagged arrays. Im Gegensatz zu zweidimensionalen Arrays erlauben gezackte Arrays, Spalten mit unterschiedlicher Länge zu speichern. Das ist, als hättest du einen Gebäudekomplex, bei dem jedes Gebäude eine andere Anzahl an Wohnungen hat – in einem Gebäude sind es 5 Wohnungen, im anderen 20 und im dritten nur eine.
Ein gezacktes Array ist ein Array, bei dem jedes Element selbst wieder ein Array ist. Die inneren Arrays (auch „Subarrays“ genannt) können dabei unterschiedlich lang sein.
Der Hauptunterschied:
- Im zweidimensionalen Array hat jede „Zeile“ (und jede „Spalte“) die gleiche Anzahl an Elementen. Beispiel: int[,] grid = new int[3, 5]; – wir haben immer 3 Zeilen mit je 5 Elementen.
- Im gezackten Array kann jede Zeile unterschiedlich lang sein! Beispiel: int[][] jagged = new int[3][]; – und erst danach initialisieren wir jede Zeile (Subarray) individuell.
So sieht das visuell aus:
| Zweidimensionales Array | Gezacktes Array | |
|---|---|---|
| Anzahl der Elemente | Streng festgelegt (z.B. 3x5) | Kann zwischen den Zeilen unterschiedlich sein |
| Indizierung | |
|
| Flexibilität | Niedrig | Hoch |
| Anwendung | Tabellen, Mathematik | Ungleichmäßige Daten: Listen von Studenten mit unterschiedlicher Anzahl an Noten, Dreiecke |
Visualisierung: Vergleich von zweidimensionalem und gezacktem Array
Zweidimensionales Array (3x3):
┌───┬───┬───┐
│ 1 │ 2 │ 3 │
├───┼───┼───┤
│ 4 │ 5 │ 6 │
├───┼───┼───┤
│ 7 │ 8 │ 9 │
└───┴───┴───┘
Gezacktes Array (unterschiedliche Längen):
┌───┬───┐
│ 1 │ 2 │
├───┼───┼───┬───┐
│ 3 │ 4 │ 5 │ 6 │
├───┼───┴───┴───┘
│ 7 │
└───┘
2. Syntax für Deklaration und Initialisierung eines gezackten Arrays
Die Deklaration eines gezackten Arrays ist nicht schlimmer als die der bisherigen Typen! Keine Angst vor doppelten eckigen Klammern:
int[][] jaggedArray = new int[3][];
Das bedeutet, wir haben ein Array mit 3 Elementen, und jedes davon ist wiederum ein Array von int. Aber die inneren Arrays sind noch nicht erstellt! Um das besser zu verstehen, schauen wir uns das genauer an.
Schrittweise Initialisierung eines gezackten Arrays
Schritt 1 – Erstellen des Hauptarrays (äußeres Array):
int[][] jaggedArray = new int[3][];
Jetzt haben wir 3 „Zeilen“, aber alle sind noch null.
Schritt 2 – Erstellen und Befüllen der inneren Arrays (Subarrays):
Zum Beispiel: Die erste Zeile soll Länge 2 haben, die zweite 4, die dritte 3:
jaggedArray[0] = new int[2]; // 2 Elemente in der ersten Zeile
jaggedArray[1] = new int[4]; // 4 Elemente in der zweiten Zeile
jaggedArray[2] = new int[3]; // 3 Elemente in der dritten Zeile
Schritt 3 – Befüllen mit Werten:
Die inneren Arrays sind ganz normale Arrays! Zum Beispiel:
jaggedArray[0][0] = 1;
jaggedArray[0][1] = 2;
jaggedArray[1][0] = 3;
jaggedArray[1][1] = 4;
jaggedArray[1][2] = 5;
jaggedArray[1][3] = 6;
jaggedArray[2][0] = 7;
jaggedArray[2][1] = 8;
jaggedArray[2][2] = 9;
Kurzinitialisierung eines gezackten Arrays
Du kannst ein gezacktes Array auch direkt erstellen und befüllen, wenn du die Werte schon kennst:
int[][] jaggedArray = new int[][]
{
new int[] { 1, 2 },
new int[] { 3, 4, 5, 6 },
new int[] { 7, 8, 9 }
};
Oder noch kürzer, indem du den Typ der inneren Arrays weglässt:
int[][] jaggedArray = {
new[] { 1, 2 },
new[] { 3, 4, 5, 6 },
new[] { 7, 8, 9 }
};
3. Durchlaufen und Arbeiten mit gezackten Arrays
Ein gezacktes Array zu durchlaufen ist nicht schwerer als ein zweidimensionales, aber jetzt läuft die äußere Schleife über die Zeilen und die innere über die Elemente der Zeile (die unterschiedlich lang sein können):
for (int i = 0; i < jaggedArray.Length; i++)
{
Console.WriteLine($"Zeile {i}:");
for (int j = 0; j < jaggedArray[i].Length; j++)
{
Console.Write($"{jaggedArray[i][j]} ");
}
Console.WriteLine();
}
Ergebnis auf dem Bildschirm:
Zeile 0:
1 2
Zeile 1:
3 4 5 6
Zeile 2:
7 8 9
Du kannst auch foreach verwenden, dann musst du dir keine Gedanken über Indizes machen:
foreach (int[] row in jaggedArray)
{
foreach (int value in row)
{
Console.Write($"{value} ");
}
Console.WriteLine();
}
4. Aufbau eines Arrays von Arrays
Jetzt erfährst du, wie Arrays von Arrays wirklich aufgebaut sind. Bereit?
Bei einem normalen Array gilt: „Die Array-Variable speichert einen Verweis auf einen Container, der die Array-Elemente enthält“. Bei gezackten Arrays ist die Sache etwas explosiver: Die Array-von-Arrays-Variable speichert einen Verweis auf einen Container, der wiederum Verweise auf eindimensionale Arrays enthält. Das sieht man besser als dass man es hundertmal erklärt:
Links haben wir die „Array-von-Arrays-Variable“, die einen Verweis auf das „Objekt-Container der Arrays“ speichert. In der Mitte ist das „Objekt-Container der Arrays“, in dessen Zellen Verweise auf eindimensionale Arrays gespeichert sind – die Zeilen des gezackten Arrays. Und rechts siehst du vier eindimensionale Arrays – die Zeilen unseres gezackten Arrays.
So sind gezackte Arrays wirklich aufgebaut. Und dieser Ansatz gibt C#-Programmierern einige Vorteile:
Erstens, da der „Container der Container“ Verweise auf „Array-Zeilen“ speichert, können wir Zeilen sehr schnell und einfach vertauschen. Um auf den „Container der Container“ zuzugreifen, reicht ein Index statt zwei. Beispiel:int[][] data = new int[2][];
data[0] = new int[5]; // erste Zeile – Array mit 5 Elementen
data[1] = new int[5]; // zweite Zeile – Array mit 5 Elementen
int[] row1 = data[0];
int[] row2 = data[1];
Mit so einem Code kannst du Zeilen vertauschen:
// Wichtige Matrix mit Daten
int[][] matrix = {
new int[] {1, 2, 3, 4, 5},
new int[] {5, 4, 3, 2, 1}
};
int[] tmp = matrix[0];
matrix[0] = matrix[1];
matrix[1] = tmp;
Wenn du auf eine Zelle eines zweidimensionalen Arrays zugreifen willst, aber nach dem Array-Namen nur einen Index angibst, greifst du auf den Container der Container zu, in dessen Zellen Verweise auf normale eindimensionale Arrays gespeichert sind.
5. Typische Anwendungsfälle für gezackte Arrays
Wann ist ein gezacktes Array nützlicher als ein zweidimensionales?
- Wenn du für jeden User eine unterschiedliche Anzahl von Daten speichern willst: Noten für Fächer, Einkäufe, Kommentare usw.
- Wenn deine Daten eine dreieckige oder stufenförmige Struktur haben (z.B. für Pyramiden, Pascalsche Dreiecke usw.).
- Wenn du Speicher sparen willst: Im zweidimensionalen Array sind alle Zeilen fix, im gezackten nur so viele Elemente wie nötig.
Beispiel aus dem Leben: Notenmanager für Studenten
Lass uns unser Lernprojekt erweitern! Jeder Student kann eine unterschiedliche Anzahl an Noten pro Fach haben. Zum Beispiel macht jemand mehr Aufgaben, jemand weniger. Dafür eignet sich ein gezacktes Array perfekt.
Angenommen, wir haben drei Studenten, und das sind ihre Noten für verschiedene Matheaufgaben:
| Student | Noten |
|---|---|
| 0 | 5, 4 |
| 1 | 3, 4, 4 |
| 2 | 5 |
Deklarieren wir so ein Array:
int[][] studentMarks = new int[3][];
studentMarks[0] = new int[] { 5, 4 }; // Erster Student - 2 Noten
studentMarks[1] = new int[] { 3, 4, 4 }; // Zweiter Student - 3 Noten
studentMarks[2] = new int[] { 5 }; // Dritter Student - 1 Note
Geben wir die Noten jedes Studenten aus:
for (int i = 0; i < studentMarks.Length; i++)
{
Console.Write($"Student {i}: ");
for (int j = 0; j < studentMarks[i].Length; j++)
{
Console.Write(studentMarks[i][j] + " ");
}
Console.WriteLine();
}
Gezackte Arrays mit anderen Typen verwenden
Ein gezacktes Array kann alles enthalten: Strings, Arrays von anderen Arrays (noch tiefer!), sogar deine eigenen Objekte.
Beispiel: Array von Strings
string[][] groups = new string[][]
{
new string[] { "Ivan", "Pjotr" },
new string[] { "Maria", "Aleksej", "Sergej" },
new string[] { "Vasilisa" }
};
6. Besonderheiten und mögliche Fehler
Gezackte Arrays sind flexibel, aber es gibt auch einige Fallen.
- Wenn du eines der inneren Arrays nicht initialisiert hast (jaggedArray[1] = ...), führt ein Zugriff darauf zu einer NullReferenceException. Vergiss nicht, jedes innere Array zu initialisieren!
- Nicht alle Zeilen (Subarrays) sind gleich lang. Wenn du einen festen Index im zweiten Index verwendest, kannst du über das Ende hinausgehen.
- Verwechsele es nicht mit einem zweidimensionalen Array! Die Indizierung sieht so aus: array[i][j], nicht array[i, j].
GO TO FULL VERSION