Array di Array in C#

Gli array di array, chiamati anche in inglese Jagged Array o Array Irregolari, rappresentano un approccio flessibile per gestire strutture di dati annidate, poiché ogni riga può contenere un numero variabile di elementi.

In C#, si costruiscono come array di array, consentendo un controllo dettagliato della memoria e dell’organizzazione dei dati. In questo articolo scopriremo come dichiararli, allocarli e utilizzarli. Inoltre, esamineremo un esempio pratico di come costruire il Triangolo di Tartaglia utilizzando un array di array.

Array di Array

In C# possiamo avere array di array, che chiamiamo jagged arrays.

I jagged arrays sono array di array, ovvero array in cui ogni riga contiene a sua volta un proprio array, e quest'ultimo può avere una lunghezza diversa rispetto alle altre righe. Questo è diverso dagli array multidimensionali, in cui tutte le righe hanno la stessa lunghezza.

Definizione

Array di Array (Jagged Arrays)

Un Jagged Array è un array in cui ogni elemento è un array. Ogni array può avere una lunghezza diversa.

Dichiarazione e Allocazione di un Array di Array

L'unica differenza nella dichiarazione dei jagged array rispetto agli array multidimensionali regolari è che non abbiamo una sola coppia di parentesi quadre.

Con i jagged array, abbiamo una coppia di parentesi quadre per dimensione.

Li allochiamo in questo modo:

int[][] jaggedArray;
jaggedArray = new int[2][];
jaggedArray[0] = new int[5];
jaggedArray[1] = new int[3];

Ecco come dichiariamo, allocchiamo e inizializziamo un array di array (un jagged array i cui elementi sono array di valori interi):

int[][] myJaggedArray = {
    new int[] {5, 7, 2},
    new int[] {10, 20, 40},
    new int[] {3, 25}
};

Da notare che ogni riga è un array che va allocato separatamente. In questo caso, myJaggedArray è un array di tre array di interi. Ogni array interno ha una lunghezza diversa.

Definizione

Dichiarazione di un Jagged Array

Per dichiarare un jagged array, usiamo la seguente sintassi:

tipo[][] nomeArray;

Allocazione in Memoria

La figura sottostante illustra come il jagged array myJaggedArray dichiarato nell'esempio di sopra sia allocato in memoria:

Disposizione in Memoria dell'array jagged
Figura 1: Disposizione in Memoria dell'array jagged

Come possiamo vedere, i jagged array sono un insieme di riferimenti. Un jagged array non contiene direttamente altri array, ma ha elementi che puntano ad essi.

La dimensione non è nota e per questo il sistema di runtime .NET (il CLR) mantiene solo riferimenti agli array interni. Dopo aver allocato la memoria per un elemento di array, quel riferimento inizia a puntare al nuovo blocco creato nella memoria dinamica.

La variabile myJaggedArray è memorizzata nello stack di esecuzione del programma e punta a un blocco nella memoria dinamica, che contiene una sequenza di tre riferimenti ad altri tre blocchi in memoria; ognuno di essi contiene un array di numeri interi, ossia gli elementi del jagged array.

Inizializzazione e Accesso agli Elementi

Possiamo accedere agli elementi degli array che fanno parte dell'array jagged utilizzando il loro indice.

Nel prossimo esempio accederemo all'elemento con indice 3 dell'array memorizzato all'indice 0 in myJaggedArray dichiarato sopra:

myJaggedArray[0][2] = 45;

Gli elementi dell'array jagged possono essere array monodimensionali oppure array multidimensionali. Ecco un esempio di jagged array di array bidimensionali:

int[,][] jaggedOfMulti = new int[2][,];

jaggedOfMulti[0] = new int[,] {
    { 5, 15 },
    { 125, 206 }
};

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

Esempio: Costruzione del Triangolo di Tartaglia

Nel prossimo esempio useremo un jagged array per generare e visualizzare il Triangolo di Tartaglia.

Come sappiamo dalla matematica, la prima riga del triangolo contiene il numero 1 e ogni numero successivo è generato dalla somma dei due numeri nella riga sopra.

Il triangolo di Tartaglia ha l'aspetto che segue:

\begin{array}{ccccccccccc} & & & & & 1 & & & & & \\ & & & & 1 & & 1 & & & & \\ & & & 1 & & 2 & & 1 & & & \\ & & 1 & & 3 & & 3 & & 1 & & \\ & 1 & & 4 & & 6 & & 4 & & 1 & \\ 1 & & 5 & & 10 & & 10 & & 5 & & 1 \\ \end{array}

Per avere un Triangolo di Tartaglia di un'altezza data (ad esempio 12), allochiamo un jagged array triangle[][], che contiene 1 elemento nella riga zero, 2 nella prima, 3 nella seconda, ecc.

Per prima cosa, inizializziamo triangle[0][0] = 1, mentre il resto delle celle avrà valore predefinito 0 grazie all'allocazione.

Poi iteriamo sulle righe e dalla riga row calcoliamo i valori per la riga row + 1. Per farlo usiamo due cicli for annidati che scorrono le colonne nella riga corrente e nella successiva, e applichiamo le definizioni del Triangolo di Tartaglia per i valori del triangolo: aggiungiamo il valore della cella corrente della riga attuale (triangle[row][col]) alla cella a sinistra nella riga successiva (triangle[row + 1][col]) e alla cella in basso a destra (triangle[row + 1][col + 1]).

Stampiamo usando un numero appropriato di spazi (usando il metodo PadLeft() della classe String), perché vogliamo che il risultato sia allineato.

Ecco il codice dell'algoritmo descritto:

class TartagliaTriangle
{
    static void Main()
    {
        // Altezza del Triangolo di Tartaglia
        const int HEIGHT = 12;

        // Allochiamo l'array in forma di triangolo
        long[][] triangle = new long[HEIGHT + 1][];

        for (int row = 0; row < HEIGHT; row++)
        {
            triangle[row] = new long[row + 1];
        }

        // Calcolo del Triangolo di Tartaglia
        triangle[0][0] = 1;
        for (int row = 0; row < HEIGHT - 1; row++)
        {
            for (int col = 0; col <= row; col++)
            {
                triangle[row + 1][col] += triangle[row][col];
                triangle[row + 1][col + 1] += triangle[row][col];
            }
        }

        // Stampa del Triangolo di Tartaglia
        for (int row = 0; row < HEIGHT; row++)
        {
            Console.Write("".PadLeft((HEIGHT - row) * 2));
            for (int col = 0; col <= row; col++)
            {
                Console.Write("{0,3} ", triangle[row][col]);
            }
            Console.WriteLine();
        }
    }
}

Se eseguiamo il programma, vedremo che funziona correttamente e genera il Triangolo di Tartaglia per un certo numero di righe (nel nostro caso HEIGHT = 12):

                          1 
                        1   1 
                      1   2   1 
                    1   3   3   1 
                  1   4   6   4   1 
                1   5  10  10   5   1 
              1   6  15  20  15   6   1 
            1   7  21  35  35  21   7   1 
          1   8  28  56  70  56  28   8   1 
        1   9  36  84 126 126  84  36   9   1 
      1  10  45 120 210 252 210 120  45  10   1 
    1  11  55 165 330 462 462 330 165  55  11   1

In Sintesi

In questa lezione abbiamo appreso che:

  • I jagged arrays sono array di array, dove ogni elemento punta a un array distinto.
  • Si allocano specificando la dimensione del contenitore esterno e poi, per ogni indice, definendo la lunghezza dell’array interno.
  • A differenza di un array multi-dimensionale classico, ogni riga può avere dimensioni differenti.
  • L’esempio del Triangolo di Tartaglia illustra come sfruttare questo modello per generare una struttura con larghezza variabile in ogni riga.
  • La gestione degli indici e delle inizializzazioni richiede attenzione, ma offre grande libertà nella gestione dei dati.