CodeGym /Corsi /C# SELF /Array dentellati (Jagged Arrays) in C#

Array dentellati (Jagged Arrays) in C#

C# SELF
Livello 7, Lezione 5
Disponibile

1. In cosa gli array dentellati sono diversi da quelli bidimensionali

Eccoci arrivati all’argomento che molti chiamano «array di array» oppure «array dentellati» — in inglese jagged arrays. A differenza degli array bidimensionali, gli array dentellati ti permettono di avere colonne di lunghezza diversa. È come se avessi un complesso di edifici, dove ogni edificio ha il suo numero di appartamenti: in uno ce ne sono 5, in un altro 20, e in un altro ancora solo uno.

Un array dentellato è un array in cui ogni elemento è a sua volta un array. E questi array interni (detti anche “sottoarray”) possono avere lunghezze diverse.

La differenza principale:

  • In un array bidimensionale ogni “riga” (e ogni “colonna”) ha sempre lo stesso numero di elementi. Esempio: int[,] grid = new int[3, 5]; — avrai sempre 3 righe da 5 elementi ciascuna.
  • In un array dentellato ogni riga può avere una lunghezza diversa! Esempio: int[][] jagged = new int[3][]; — e solo dopo inizializzi ogni riga (sottoarray) come vuoi tu.

Ecco come si presenta visivamente:

Array bidimensionale Array dentellato
Numero di elementi Fisso (per esempio, 3x5) Può variare tra le righe
Indicizzazione
[i, j]
[i][j]
Flessibilità Bassa Alta
Utilizzo Tabelle, matematica Dati non uniformi:
liste di studenti con numero diverso di voti, triangoli

Visualizzazione: confronto tra array bidimensionale e dentellato

Array bidimensionale (3x3):
┌───┬───┬───┐
│ 1 │ 2 │ 3 │
├───┼───┼───┤
│ 4 │ 5 │ 6 │
├───┼───┼───┤
│ 7 │ 8 │ 9 │
└───┴───┴───┘

Array dentellato (lunghezze diverse):
┌───┬───┐
│ 1 │ 2 │
├───┼───┼───┬───┐
│ 3 │ 4 │ 5 │ 6 │
├───┼───┴───┴───┘
│ 7 │
└───┘

2. Sintassi di dichiarazione e inizializzazione di un array dentellato

Dichiarare un array dentellato non è più difficile che dichiarare altri tipi! Non farti spaventare dalle doppie parentesi quadre:

int[][] jaggedArray = new int[3][];
Dichiarazione di un array dentellato

Questo significa che hai un array di 3 elementi, e ognuno di questi è a sua volta un array di int. Ma per ora gli array interni non sono ancora stati creati! Per capirlo meglio, vediamolo passo passo.

Inizializzazione passo-passo di un array dentellato

Passo 1 — creazione dell’array principale (esterno):

int[][] jaggedArray = new int[3][];

Ora hai 3 “righe”, ma tutte sono ancora null.

Passo 2 — creazione e riempimento degli array interni (sottoarray):

Per esempio, la prima riga sarà lunga 2, la seconda 4, la terza 3:

jaggedArray[0] = new int[2]; // 2 elementi nella prima riga
jaggedArray[1] = new int[4]; // 4 elementi nella seconda riga
jaggedArray[2] = new int[3]; // 3 elementi nella terza riga

Passo 3 — riempimento con valori:

Gli array interni sono array normali! Per esempio:

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;

Inizializzazione rapida di un array dentellato

Puoi creare e riempire subito un array dentellato, se conosci già i valori:

int[][] jaggedArray = new int[][]
{
    new int[] { 1, 2 },
    new int[] { 3, 4, 5, 6 },
    new int[] { 7, 8, 9 }
};

O ancora più corto, senza specificare il tipo degli array interni:

int[][] jaggedArray = {
    new[] { 1, 2 },
    new[] { 3, 4, 5, 6 },
    new[] { 7, 8, 9 }
};

3. Iterare e lavorare con gli array dentellati

Iterare un array dentellato non è più difficile che con uno bidimensionale, ma ora il ciclo esterno va sulle righe, e quello interno sugli elementi della riga (che possono avere lunghezze diverse):

for (int i = 0; i < jaggedArray.Length; i++)
{
    Console.WriteLine($"Riga {i}:");
    for (int j = 0; j < jaggedArray[i].Length; j++)
    {
        Console.Write($"{jaggedArray[i][j]} ");
    }
    Console.WriteLine();
}

Risultato a schermo:

Riga 0:
1 2 
Riga 1:
3 4 5 6 
Riga 2:
7 8 9 

Puoi usare anche foreach, così non devi pensare agli indici:

foreach (int[] row in jaggedArray)
{
    foreach (int value in row)
    {
        Console.Write($"{value} ");
    }
    Console.WriteLine();
}

4. Struttura di un array di array

E ora vediamo come sono fatti davvero gli array di array. Pronti?

Se con un array normale “la variabile-array contiene un riferimento al contenitore che tiene gli elementi dell’array”, con gli array dentellati la situazione è un po’ più esplosiva: la variabile-array-di-array contiene un riferimento a un contenitore che tiene riferimenti ad array monodimensionali. È meglio vederlo una volta che spiegarlo cento volte:

How two-dimensional arrays work

A sinistra abbiamo la “variabile-array-di-array” che contiene un riferimento all’“oggetto-contenitore di array”. Al centro c’è l’“oggetto-contenitore di array”, nelle cui celle ci sono riferimenti ad array monodimensionali — le righe dell’array dentellato. E a destra vedi quattro array monodimensionali — le righe del nostro array dentellato.

Ecco come sono fatti davvero gli array dentellati. E questo approccio dà a chi programma in C# diversi vantaggi:

Primo, siccome il “contenitore di contenitori” tiene riferimenti agli “array-riga”, puoi cambiare le righe molto velocemente e facilmente. Per accedere al “contenitore di contenitori” basta un solo indice invece di due. Esempio:
int[][] data = new int[2][];
data[0] = new int[5]; // prima riga — array di 5 elementi
data[1] = new int[5]; // seconda riga — array di 5 elementi

int[] row1 = data[0];
int[] row2 = data[1];

Ecco come puoi scambiare le righe tra loro:

// Matrice importante con dati
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;

Se accedi a una cella di un array bidimensionale ma dopo il nome dell’array metti solo un indice, così accedi al contenitore di contenitori, nelle cui celle ci sono riferimenti ad array monodimensionali.

5. Scenari tipici di utilizzo degli array dentellati

Quando un array dentellato può essere più utile di uno bidimensionale?

  • Se per ogni utente devi memorizzare un numero diverso di dati: voti per materia, acquisti, commenti e così via.
  • Se i tuoi dati hanno una struttura a triangolo o a gradini (per esempio, per stampare piramidi, triangoli di Pascal, ecc.).
  • Se vuoi risparmiare memoria: in un array bidimensionale tutte le righe sono fisse, in uno dentellato solo il numero necessario di elementi.

Esempio reale: gestore dei voti degli studenti

Facciamo crescere il nostro progetto! Ogni studente può avere un numero diverso di voti per ogni materia. Per esempio, qualcuno fa più compiti, qualcuno meno. Per questo un array dentellato è perfetto.

Supponiamo di avere tre studenti, e questi sono i loro voti per vari compiti di matematica:

Studente Voti
0 5, 4
1 3, 4, 4
2 5

Dichiariamo questo array:

int[][] studentMarks = new int[3][];
studentMarks[0] = new int[] { 5, 4 };         // Primo studente - 2 voti
studentMarks[1] = new int[] { 3, 4, 4 };      // Secondo studente - 3 voti
studentMarks[2] = new int[] { 5 };            // Terzo studente - 1 voto

Stampiamo i voti di ogni studente:

for (int i = 0; i < studentMarks.Length; i++)
{
    Console.Write($"Studente {i}: ");
    for (int j = 0; j < studentMarks[i].Length; j++)
    {
        Console.Write(studentMarks[i][j] + " ");
    }
    Console.WriteLine();
}

Uso degli array dentellati con altri tipi

Un array dentellato può essere di qualsiasi cosa: stringhe, array di altri array (ancora più in profondità!), anche dei tuoi oggetti personalizzati.

Esempio: array di stringhe

string[][] groups = new string[][]
{
    new string[] { "Ivan", "Petr" },
    new string[] { "Maria", "Aleksei", "Sergei" },
    new string[] { "Vasilisa" }
};

6. Caratteristiche e possibili errori

Gli array dentellati sono super flessibili, ma le trappole sono sempre dietro l’angolo.

  • Se non hai inizializzato uno degli array interni (jaggedArray[1] = ...), provare ad accedervi ti darà un NullReferenceException. Ricordati di inizializzare ogni array interno!
  • Non tutte le righe (sottoarray) hanno la stessa lunghezza. Se usi un indice fisso nella seconda dimensione, puoi andare fuori dai limiti.
  • Non confonderli con gli array bidimensionali! L’indicizzazione è così: array[i][j], non array[i, j].
2
Compito
C# SELF, livello 7, lezione 5
Bloccato
Dichiarazione e inizializzazione di un semplice array jagged
Dichiarazione e inizializzazione di un semplice array jagged
2
Compito
C# SELF, livello 7, lezione 5
Bloccato
Il valore massimo in un array jagged
Il valore massimo in un array jagged
1
Sondaggio/quiz
Array, livello 7, lezione 5
Non disponibile
Array
Introduzione agli array
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION