CodeGym /Kurse /C# SELF /Gezackte Arrays (Jagged Arrays) in C#

Gezackte Arrays (Jagged Arrays) in C#

C# SELF
Level 7 , Lektion 5
Verfügbar

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
[i, j]
[i][j]
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][];
Deklaration eines gezackten Arrays

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:

How two-dimensional arrays work

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].
1
Umfrage/Quiz
Arrays, Level 7, Lektion 5
Nicht verfügbar
Arrays
Einführung in Arrays
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION