Array Multi-dimensionali in C#
Le matrici multidimensionali sono strutture fondamentali in C# e permettono di gestire con semplicità dati disposti su più dimensioni.
In questo articolo scopriremo come dichiararle, inizializzarle e utilizzarle, esaminando anche alcuni esempi pratici. Impareremo a leggere e scrivere valori da console e a risolvere problemi di una certa complessità.
Array Multidimensionali
Gli array monodimensionali sono conosciuti anche come vettori in matematica.
Spesso abbiamo bisogno di array con più di una dimensione. Ad esempio, possiamo facilmente rappresentare una scacchiera standard come un array bidimensionale di dimensioni 8 per 8 (8 celle in direzione orizzontale e 8 celle in direzione verticale).
Ogni tipo valido in C# può essere usato come tipo di un array. Quindi possiamo avere un array di array, di cui parleremo nelle prossime lezioni.
Dichiariamo un array monodimensionale di numeri interi usando int[]
, e dichiariamo un bidimensionale con int[,]
. Ecco un esempio:
int[,] arrayBidimensionale;
Questi array li chiameremo bidimensionali, perché hanno due dimensioni. Sono noti anche come matrici (termine matematico). Gli array generali con più di due dimensioni li chiameremo multidimensionali.
In questo modo possiamo dichiarare array tridimensionali aggiungendo una dimensione in più:
int[,,] arrayTridimensionale;
In teoria non c'è limite al numero di dimensioni di un array, ma in pratica non usiamo array con molte dimensioni, quindi ci concentreremo sugli array bidimensionali.
Array Multidimensionali
Un Array Multidimensionale è un array con due o più dimensioni. Ogni dimensione è separata da una virgola. Gli array bidimensionali sono chiamati anche matrici.
Dichiarazione e Allocazione di Array Multidimensionali
Dichiariamo gli array multidimensionali in modo simile agli array monodimensionali. Ogni dimensione, eccetto la prima, è marcata con la virgola nelle parentesi quadre []
.
Esempio:
int[,] matriceInteri;
float[,] matriceFloat;
string[,,] cuboStringhe;
Nell'esempio sopra creiamo due array bidimensionali e un array tridimensionale. Ogni dimensione è rappresentata da una virgola tra le parentesi quadre []
.
Allochiamo la memoria per gli array multidimensionali usando la parola chiave new
e, per ogni dimensione, impostiamo una lunghezza nelle parentesi, come mostrato:
int[,] matriceInteri = new int[3, 4];
float[,] matriceFloat = new float[8, 2];
string[,,] cuboStringhe = new string[5, 5, 5];
In questo esempio, intMatrix
è un array bidimensionale con 3 elementi di tipo int[]
e ognuno di questi 3 elementi ha una lunghezza di 4. Gli array bidimensionali sono difficili da capire spiegati in questo modo. Quindi possiamo immaginarli come matrici bidimensionali, che hanno righe e colonne per le dimensioni:
Le righe e le colonne delle matrici quadrate sono numerate con indici da 0 a n-1. Se un array bidimensionale ha dimensioni
Ricapitolando:
Dichiarazione di un Array Multidimensionale
Per dichiarare un array bidimensionale, usiamo la seguente sintassi:
tipoDati[,] nomeArray;
Se vogliamo dichiarare un array con un numero di dimensioni maggiore di due, aggiungiamo una virgola per ogni dimensione aggiuntiva:
tipoDati[,,] array3D;
tipoDati[,,,] array4D;
tipoDati[,,,,] array5D;
In generale il numero delle dimensioni è dato dal numero di virgole più uno.
Allocazione di un Array Multidimensionale
Per allocare un array multidimensionale, usiamo la parola chiave new
e specifichiamo le grandezze di ciascuna dimensione tra parentesi quadre:
tipoDati[,] nomeArray = new tipoDati[dimensione1, dimensione2];
Inizializzazione di un Array Bidimensionale
Possiamo inizializzare gli array bidimensionali nello stesso modo in cui inizializziamo gli array monodimensionali. Possiamo elencare i valori degli elementi subito dopo la dichiarazione:
int[,] matrice =
{
{1, 2, 3, 4}, // valori della riga 0
{5, 6, 7, 8}, // valori della riga 1
};
// La dimensione della matrice è 2 x 4 (2 righe, 4 colonne)
Nell'esempio sopra, inizializziamo un array bidimensionale di tipo int
con dimensione di 2 righe e 4 colonne.
Nelle parentesi più esterne mettiamo gli elementi della prima dimensione, cioè le righe dell'array. Ogni riga contiene un array monodimensionale, che sappiamo inizializzare.
Inizializzazione di un Array Multidimensionale
Un array può essere inizializzato in fase di dichiarazione. Per inizializzare un array multidimensionale, elenchiamo i valori degli elementi subito dopo la dichiarazione:
tipoDati[,] nomeArray =
{
{valoriRiga0},
{valoriRiga1},
/* ... */
};
Accesso agli Elementi di un Array Multidimensionale
Le matrici hanno due dimensioni e di conseguenza accediamo a ciascun elemento usando due indici: uno per le righe e uno per le colonne.
Gli array multidimensionali hanno indici diversi per ogni dimensione.
In C# anche gli array multidimensionali sono Zero-Based
Così come per gli array mono-dimensionali, anche gli array multidimensionali iniziano con l'indice 0. In particolare ogni dimensione in un array multidimensionale inizia sempre dall'indice 0.
Esaminiamo il seguente esempio:
int[,] matrice =
{
{1, 2, 3, 4},
{5, 6, 7, 8},
};
L'array matrice
ha 8 elementi, memorizzati in 2 righe e 4 colonne. Ogni elemento può essere accessibile nel seguente modo:
matrice[0, 0] matrice[0, 1] matrice[0, 2] matrice[0, 3]
matrice[1, 0] matrice[1, 1] matrice[1, 2] matrice[1, 3]
In questo esempio, possiamo accedere a ogni elemento usando gli indici. Se assegniamo l'indice per le righe a riga
e l'indice per le colonne a col
, possiamo accedere a qualunque elemento come:
matrice[riga, col]
Quando usiamo array multidimensionali, ogni elemento è univoco e può essere identificato con gli indici dell'array:
nDimensionalArray[index1, ..., indexN]
Lunghezza degli Array Multidimensionali
Ogni dimensione di un array multidimensionale ha la propria lunghezza, che può essere recuperata durante l'esecuzione del programma.
Vediamo un esempio di un array bidimensionale:
int[,] matrice =
{
{1, 2, 3, 4},
{5, 6, 7, 8},
};
Possiamo ottenere il numero di righe di questo array bidimensionale usando matrice.GetLength(0)
e il numero di colonne per riga con matrice.GetLength(1)
. Quindi, in questo caso, matrice.GetLength(0)
restituisce 2 e matrice.GetLength(1)
restituisce 4.
Ottenere la Lunghezza delle dimensioni di un Array Multidimensionale
Per ottenere la lunghezza di una dimensione di un array multidimensionale, usiamo il metodo GetLength(dimensione)
:
int lunghezzaRighe = nomeArray.GetLength(0);
int lunghezzaColonne = nomeArray.GetLength(1);
Esempio: Stampa di una Matrice su Console
Nel prossimo esempio dimostreremo come stampare array bidimensionali sulla console:
// Dichiarare e inizializzare una matrice di dimensioni 2 x 4
int[,] matrix =
{
{1, 2, 3, 4}, // valori della riga 0
{5, 6, 7, 8}, // valori della riga 1
};
// Stampare la matrice sulla console
for (int row = 0; row < matrix.GetLength(0); row++)
{
for (int col = 0; col < matrix.GetLength(1); col++)
{
Console.Write(matrix[row, col]);
}
Console.WriteLine();
}
Per prima cosa dichiariamo e inizializziamo un array che vogliamo iterare e stampare su console.
L'array è bidimensionale, quindi useremo un for
esterno che itera sulle righe e un for
annidato che, per ogni riga, itererà sulle colonne. A ogni iterazione stampiamo l'elemento corrente usando il metodo appropriato per accedere a questo elemento con i suoi due indici (riga e colonna).
Infine, se eseguiamo questo pezzo di codice otterremo il seguente risultato:
1 2 3 4
5 6 7 8
Esempio: Lettura di una Matrice da Console
In questo esempio impareremo come leggere un array bidimensionale dalla console.
Prima leggiamo i valori (lunghezze) delle due dimensioni e poi, usando due cicli for
annidati, assegniamo il valore di ogni elemento (e alla fine stampiamo i valori dell'array):
Console.Write("Inserisci il numero di Righe: ");
int rows = int.Parse(Console.ReadLine());
Console.Write("Inserisci il numero di Colonne: ");
int cols = int.Parse(Console.ReadLine());
int[,] matrix = new int[rows, cols];
Console.WriteLine("Inserisci gli elementi della Matrice:");
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
{
Console.Write("matrix[{row},{col}] = ", row, col);
matrix[row, col] = int.Parse(Console.ReadLine());
}
}
for (int row = 0; row < matrix.GetLength(0); row++)
{
for (int col = 0; col < matrix.GetLength(1); col++)
{
Console.Write(" " + matrix[row, col]);
}
Console.WriteLine();
}
Il risultato del programma quando lo eseguiamo (nel caso l'array sia composto da tre righe e due colonne) è:
Inserisci il numero di Righe: 3
Inserisci il numero di Colonne: 2
Inserisci gli elementi della Matrice:
matrix[0,0] = 2
matrix[0,1] = 3
matrix[1,0] = 5
matrix[1,1] = 10
matrix[2,0] = 8
matrix[2,1] = 9
2 3
5 10
8 9
Esempio: Sotto-matrice con Somma Massima
Nel prossimo esempio risolveremo un altro problema interessante: ci viene dato un array rettangolare bidimensionale (matrix
) di numeri interi e il nostro compito è trovare la sottomatrice di dimensioni 2 x 2 con la somma massima dei suoi elementi e stamparla a console.
Una possibile soluzione al problema potrebbe essere la seguente:
class MaxSubMatrix2x2
{
static void Main()
{
// Dichiarare e inizializzare la matrice
int[,] matrix =
{
{ 0, 2, 4, 0, 9, 5 },
{ 7, 1, 3, 3, 2, 1 },
{ 1, 3, 9, 8, 5, 6 },
{ 4, 6, 7, 9, 1, 0 }
};
// Trovare la sotto-matrice di somma massima di dimensioni 2 x 2
long bestSum = long.MinValue;
int bestRow = 0;
int bestCol = 0;
for (int row = 0; row < matrix.GetLength(0) - 1; row++)
{
for (int col = 0; col < matrix.GetLength(1) - 1; col++)
{
long sum = matrix[row, col] + matrix[row, col + 1] +
matrix[row + 1, col] + matrix[row + 1, col + 1];
if (sum > bestSum)
{
bestSum = sum;
bestRow = row;
bestCol = col;
}
}
}
// Stampare il risultato
Console.WriteLine("La Sotto-Matrice di Somma Massima è:");
Console.WriteLine(" {0} {1}",
matrix[bestRow, bestCol],
matrix[bestRow, bestCol + 1]);
Console.WriteLine(" {0} {1}",
matrix[bestRow + 1, bestCol],
matrix[bestRow + 1, bestCol + 1]);
Console.WriteLine("La somma massima è: {0}", bestSum);
}
}
Se eseguiamo il programma, vedremo che funziona correttamente:
La Sotto-Matrice di Somma Massima è:
9 8
7 9
La somma massima è: 33
Spiegazione dell'esempio
Per prima cosa creiamo un array bidimensionale che contiene numeri interi.
Dichiariamo le variabili ausiliarie bestSum
, bestRow
, bestCol
e inizializziamo bestSum
con il valore minimo di tipo long
(così qualunque altro valore sarà maggiore di questo).
Si noti che la somma di 4 interi potrebbe non entrare in int
, quindi usiamo long
.
Nella variabile bestSum
manteniamo la somma massima corrente, mentre in bestRow
e bestCol
manteniamo la sotto-matrice corrente migliore. Ciò significa che la riga corrente (row
) e la colonna corrente (col
) descrivono l'elemento di partenza della sotto-matrice di dimensioni 2 x 2, che al momento risulta avere la somma massima dei suoi elementi.
Per accedere a tutti gli elementi di una sotto-matrice di dimensioni 2 x 2 ci servono gli indici del primo elemento:
matrix[row, col]
matrix[row, col + 1]
matrix[row + 1, col]
matrix[row + 1, col + 1]
In questo esempio, row
e col
sono gli indici del primo elemento della sotto-matrice di dimensioni 2 x 2, che fa parte dell'array matrix
.
Dopo aver compreso come accedere ai quattro elementi della matrice con dimensioni 2 x 2, a partire da una determinata riga e colonna, analizziamo l'algoritmo che useremo per trovare la sotto-matrice massima:
- Dobbiamo iterare tra ogni sotto-blocco 2 x 2 della matrice fino a trovare la sotto-matrice con la somma migliore. Lo facciamo usando due cicli
for
annidati e due variabilirow
ecol
. - Si noti che non iteriamo l'intera matrice, perché se provassimo ad accedere a
row + 1
ocol + 1
, quando siamo all'ultima riga o colonna, usciremmo dai limiti della matrice e verrebbe sollevata un'eccezioneSystem.IndexOutOfRangeException
. - Accediamo agli elementi vicini di ogni elemento della sotto-matrice e li sommiamo. Quindi controlliamo se la somma corrente è maggiore della somma massima attuale. Se sì, la nostra somma corrente diventa la nuova somma migliore e i nostri indici correnti aggiorneranno
bestRow
ebestCol
. - Alla fine dell'iterazione sull'intera matrice, avremo trovato la somma massima e l'indice del primo elemento della sotto-matrice 2 x 2 di dimensione massima, insieme ai suoi indici.
Se esiste più di una sotto-matrice con la stessa somma massima, troveremo la prima che appare.
Al termine dell'esempio, stampiamo a console la sotto-matrice richiesta di dimensioni 2 x 2 e la sua somma di elementi in modo appropriato.
In Sintesi
In questo articolo abbiamo visto che:
- Le variabili di tipo array possono essere bidimensionali o persino multi-dimensionali, a seconda delle esigenze.
- Ogni dimensione è gestita da indici separati, a partire da 0, consentendo di accedere a ciascun elemento in modo preciso.
- La proprietà
GetLength(dim)
permette di conoscere la dimensione di ogni livello, mentre i ciclifor
annidati consentono di iterare e processare i valori. - L'esempio sulla ricerca della sotto-matrice 2 x 2 con somma massima mostra come scorrere sistematicamente gli elementi senza uscire dai limiti dell'array, individuando la combinazione più vantaggiosa.
- Queste conoscenze permettono di affrontare molte situazioni reali in cui i dati sono organizzati in righe e colonne.