Condividi tramite


Matrici

È possibile archiviare più variabili dello stesso tipo in una struttura di dati a matrice. Una matrice viene dichiarata specificando il tipo degli elementi. Se si desidera che la matrice archivi elementi di qualsiasi tipo, è possibile specificare object come tipo. Nel sistema di tipi unificato di C#, tutti i tipi, predefiniti e definiti dall'utente, i tipi riferimento e i tipi valore ereditano direttamente o indirettamente da Object.

type[] arrayName;

Una matrice è un tipo di riferimento, pertanto la matrice può essere un tipo di riferimento nullable. I tipi di elemento possono essere tipi di riferimento, pertanto una matrice può essere dichiarata in modo da contenere tipi di riferimento nullable. Le dichiarazioni di esempio seguenti mostrano la diversa sintassi usata per dichiarare la nullabilità dell'array o degli elementi.

type?[] arrayName; // non nullable array of nullable element types.
type[]? arrayName; // nullable array of non-nullable element types.
type?[]? arrayName; // nullable array of nullable element types.

Gli elementi non inizializzati in una matrice vengono impostati sul valore predefinito per quel tipo:

int[] numbers = new int[10]; // All values are 0
string[] messages = new string[10]; // All values are null.

Importante

Nell'esempio precedente, anche se il tipo è string[], una matrice di stringhe non annullabili, il valore predefinito per ogni elemento è null. Il modo migliore per inizializzare un array a valori diversi da null consiste nell'usare espressioni di raccolta .

Le matrici hanno le proprietà seguenti:

  • Una matrice può essere unidimensionale, multidimensionale o irregolare.
  • Il numero di dimensioni viene impostato quando viene dichiarata una variabile di matrice. La lunghezza di ogni dimensione viene stabilita quando viene creata l'istanza della matrice. Questi valori non possono essere modificati per la durata dell'istanza.
  • Una “jagged array” è una matrice di matrici e ogni matrice di membri ha il valore predefinito di null.
  • Le matrici sono a indice zero. Una matrice con n elementi viene indicizzata da 0 a n-1.
  • Gli elementi di una matrice possono essere di qualsiasi tipo, anche di tipo matrice.
  • I tipi matrice sono tipi di riferimento derivati dal tipo di base astratto Array. Tutte le matrici implementano IList e IEnumerable. È possibile usare l'istruzione foreach per scorrere una matrice. Le matrici unidimensionali implementano anche IList<T> e IEnumerable<T>.

Gli elementi di una matrice possono essere inizializzati in valori noti al momento della creazione della matrice. A partire da C# 12, è possibile inizializzare tutti i tipi di raccolta usando un'espressione Collection. Gli elementi non inizializzati vengono impostati sul valore predefinito. Il valore predefinito è il modello a 0 bit. Tutti i tipi riferimento (inclusi i tipi che non ammettono i valori Null), hanno i valori null. Tutti i tipi valore hanno i modelli a 0 bit. Ciò significa che la proprietà Nullable<T>.HasValue è false e la proprietà Nullable<T>.Value non è definita. Nell'implementazione di .NET la proprietà Value genera un'eccezione.

L'esempio seguente consente di creare matrici unidimensionali, multidimensionali e irregolari:

// Declare a single-dimensional array of 5 integers.
int[] array1 = new int[5];

// Declare and set array element values.
int[] array2 = [1, 2, 3, 4, 5, 6];

// Declare a two dimensional array.
int[,] multiDimensionalArray1 = new int[2, 3];

// Declare and set array element values.
int[,] multiDimensionalArray2 = { { 1, 2, 3 }, { 4, 5, 6 } };

// Declare a jagged array.
int[][] jaggedArray = new int[6][];

// Set the values of the first array in the jagged array structure.
jaggedArray[0] = [1, 2, 3, 4];

Importante

Molti esempi in questo articolo usano espressioni di raccolta (con parentesi quadrate) per avviare le matrici. Le espressioni di raccolta sono state introdotte per la prima volta in C# 12, incluso in .NET 8. Se non è ancora possibile eseguire l'aggiornamento a C# 12, usare { e } per inizializzare le matrici.

// Collection expressions:
int[] array = [1, 2, 3, 4, 5, 6];
// Alternative syntax:
int[] array2 = {1, 2, 3, 4, 5, 6};

Matrici unidimensionali

Una matrice unidimensionale è una sequenza di elementi simili. È possibile accedere a un elemento tramite il relativo indice. L'indice è la posizione ordinale nella sequenza. Il primo elemento della matrice è in corrispondenza dell'indice 0. Si crea una matrice unidimensionale usando il nuovo operatore che specifica il tipo di elemento e il numero di elementi della matrice. L'esempio seguente dichiara e inizializza matrici unidimensionali:

int[] array = new int[5];
string[] weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];

Console.WriteLine(weekDays[0]);
Console.WriteLine(weekDays[1]);
Console.WriteLine(weekDays[2]);
Console.WriteLine(weekDays[3]);
Console.WriteLine(weekDays[4]);
Console.WriteLine(weekDays[5]);
Console.WriteLine(weekDays[6]);

/*Output:
Sun
Mon
Tue
Wed
Thu
Fri
Sat
*/

La prima dichiarazione dichiara una matrice non inizializzata di cinque interi, da array[0] a array[4]. Gli elementi della matrice vengono inizializzati sul valore predefinito del tipo di elemento, 0 per i numeri interi. La seconda dichiarazione dichiara una matrice di stringhe e inizializza tutti e sette i valori di tale matrice. Una serie di istruzioni Console.WriteLine stampa tutti gli elementi della matrice di weekDay. Per le matrici unidimensionali, l'istruzione foreach elabora gli elementi in ordine di indice crescente, a partire dall'indice 0 e terminando con l'indice Length - 1.

Passaggio di matrici unidimensionali come argomenti

È possibile passare una matrice unidimensionale inizializzata a un metodo. Nell'esempio seguente, una matrice di stringhe viene inizializzata e passata come argomento a un metodo DisplayArray per le stringhe. Nel metodo vengono visualizzati gli elementi della matrice. Successivamente, il metodo ChangeArray inverte gli elementi della matrice e quindi il metodo ChangeArrayElements consente di modificare i primi tre elementi della matrice. Al termine delle restituzioni di ogni metodo, il metodo DisplayArray mostra che il passaggio di una matrice per valore non impedisce le modifiche agli elementi della matrice.

class ArrayExample
{
    static void DisplayArray(string[] arr) => Console.WriteLine(string.Join(" ", arr));

    // Change the array by reversing its elements.
    static void ChangeArray(string[] arr) => Array.Reverse(arr);

    static void ChangeArrayElements(string[] arr)
    {
        // Change the value of the first three array elements.
        arr[0] = "Mon";
        arr[1] = "Wed";
        arr[2] = "Fri";
    }

    static void Main()
    {
        // Declare and initialize an array.
        string[] weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
        // Display the array elements.
        DisplayArray(weekDays);
        Console.WriteLine();

        // Reverse the array.
        ChangeArray(weekDays);
        // Display the array again to verify that it stays reversed.
        Console.WriteLine("Array weekDays after the call to ChangeArray:");
        DisplayArray(weekDays);
        Console.WriteLine();

        // Assign new values to individual array elements.
        ChangeArrayElements(weekDays);
        // Display the array again to verify that it has changed.
        Console.WriteLine("Array weekDays after the call to ChangeArrayElements:");
        DisplayArray(weekDays);
    }
}
// The example displays the following output:
//         Sun Mon Tue Wed Thu Fri Sat
//
//        Array weekDays after the call to ChangeArray:
//        Sat Fri Thu Wed Tue Mon Sun
//
//        Array weekDays after the call to ChangeArrayElements:
//        Mon Wed Fri Wed Tue Mon Sun

Matrici multidimensionali

Le matrici possono avere più di una dimensione. Ad esempio, le dichiarazioni seguenti creano quattro matrici. Due matrici hanno due dimensioni. Due matrici hanno tre dimensioni. Le prime due dichiarazioni dichiarano la lunghezza di ogni dimensione, ma non inizializzano i valori della matrice. Le seconde due dichiarazioni usano un inizializzatore per impostare i valori di ciascun elemento nella matrice multidimensionale.

int[,] array2DDeclaration = new int[4, 2];

int[,,] array3DDeclaration = new int[4, 2, 3];

// Two-dimensional array.
int[,] array2DInitialization =  { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
// Three-dimensional array.
int[,,] array3D = new int[,,] { { { 1, 2, 3 }, { 4,   5,  6 } },
                                { { 7, 8, 9 }, { 10, 11, 12 } } };

// Accessing array elements.
System.Console.WriteLine(array2DInitialization[0, 0]);
System.Console.WriteLine(array2DInitialization[0, 1]);
System.Console.WriteLine(array2DInitialization[1, 0]);
System.Console.WriteLine(array2DInitialization[1, 1]);

System.Console.WriteLine(array2DInitialization[3, 0]);
System.Console.WriteLine(array2DInitialization[3, 1]);
// Output:
// 1
// 2
// 3
// 4
// 7
// 8

System.Console.WriteLine(array3D[1, 0, 1]);
System.Console.WriteLine(array3D[1, 1, 2]);
// Output:
// 8
// 12

// Getting the total count of elements or the length of a given dimension.
var allLength = array3D.Length;
var total = 1;
for (int i = 0; i < array3D.Rank; i++)
{
    total *= array3D.GetLength(i);
}
System.Console.WriteLine($"{allLength} equals {total}");
// Output:
// 12 equals 12

Per le matrici multidimensionali, l'attraversamento degli elementi avviene in modo da incrementare per primi gli indici della dimensione all'estrema destra, per poi proseguire con la dimensione successiva a sinistra e così via, nell’indice più a sinistra. L'esempio seguente enumera sia una matrice 2D che una matrice 3D:

int[,] numbers2D = { { 9, 99 }, { 3, 33 }, { 5, 55 } };

foreach (int i in numbers2D)
{
    System.Console.Write($"{i} ");
}
// Output: 9 99 3 33 5 55

int[,,] array3D = new int[,,] { { { 1, 2, 3 }, { 4,   5,  6 } },
                        { { 7, 8, 9 }, { 10, 11, 12 } } };
foreach (int i in array3D)
{
    System.Console.Write($"{i} ");
}
// Output: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12

In una matrice 2D è possibile considerare l'indice sinistro come riga e l’indice destro come colonna.

Con le matrici multidimensionali, tuttavia, l'uso di un ciclo annidato for fornisce maggiore controllo sull'ordine di elaborazione degli elementi della matrice:

int[,,] array3D = new int[,,] { { { 1, 2, 3 }, { 4,   5,  6 } },
                        { { 7, 8, 9 }, { 10, 11, 12 } } };

for (int i = 0; i < array3D.GetLength(0); i++)
{
    for (int j = 0; j < array3D.GetLength(1); j++)
    {
        for (int k = 0; k < array3D.GetLength(2); k++)
        {
            System.Console.Write($"{array3D[i, j, k]} ");
        }
        System.Console.WriteLine();
    }
    System.Console.WriteLine();
}
// Output (including blank lines): 
// 1 2 3
// 4 5 6
// 
// 7 8 9
// 10 11 12
//

Passaggio di matrici multidimensionali come argomenti

Una matrice multidimensionale inizializzata viene passata a un metodo nello stesso modo in cui viene passata una matrice unidimensionale. Nel codice seguente viene illustrata una dichiarazione parziale di un metodo di stampa che accetta una matrice bidimensionale come argomento. È possibile inizializzare e passare una nuova matrice in un passaggio, come mostrato nell'esempio seguente. Nell'esempio seguente, una matrice bidimensionale di Integer viene inizializzata e passata al metodo Print2DArray. Nel metodo vengono visualizzati gli elementi della matrice.

static void Print2DArray(int[,] arr)
{
    // Display the array elements.
    for (int i = 0; i < arr.GetLength(0); i++)
    {
        for (int j = 0; j < arr.GetLength(1); j++)
        {
            System.Console.WriteLine("Element({0},{1})={2}", i, j, arr[i, j]);
        }
    }
}
static void ExampleUsage()
{
    // Pass the array as an argument.
    Print2DArray(new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } });
}
/* Output:
    Element(0,0)=1
    Element(0,1)=2
    Element(1,0)=3
    Element(1,1)=4
    Element(2,0)=5
    Element(2,1)=6
    Element(3,0)=7
    Element(3,1)=8
*/

Matrici di matrici

Una matrice di matrici è una matrice i cui elementi sono costituiti da matrici, possibilmente di dimensioni diverse. Una matrice di matrici è chiamata talvolta "matrice irregolare". I relativi elementi sono tipi riferimento e vengono inizializzati in null. Gli esempi seguenti mostrano come dichiarare, inizializzare e accedere a matrici di matrici. Il primo esempio, jaggedArray, viene dichiarato in un'unica istruzione. Ogni matrice contenuta viene creata nelle istruzioni successive. Il secondo esempio, jaggedArray2 viene dichiarato e inizializzato in un'unica istruzione. È possibile combinare matrici di matrici e matrici multidimensionali. L’esempio finale, jaggedArray3, è la dichiarazione e l'inizializzazione di una matrice di matrici unidimensionale che contiene tre elementi matrice bidimensionali con dimensioni diverse.

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

jaggedArray[0] = [1, 3, 5, 7, 9];
jaggedArray[1] = [0, 2, 4, 6];
jaggedArray[2] = [11, 22];

int[][] jaggedArray2 = 
[
    [1, 3, 5, 7, 9],
    [0, 2, 4, 6],
    [11, 22]
];

// Assign 77 to the second element ([1]) of the first array ([0]):
jaggedArray2[0][1] = 77;

// Assign 88 to the second element ([1]) of the third array ([2]):
jaggedArray2[2][1] = 88;

int[][,] jaggedArray3 =
[
    new int[,] { {1,3}, {5,7} },
    new int[,] { {0,2}, {4,6}, {8,10} },
    new int[,] { {11,22}, {99,88}, {0,9} }
];

Console.Write("{0}", jaggedArray3[0][1, 0]);
Console.WriteLine(jaggedArray3.Length);

Prima di poterli usare, è necessario inizializzare gli elementi di una matrice di matrici. Ognuno degli elementi è una matrice. È inoltre possibile usare gli inizializzatori per riempire gli elementi della matrice con dei valori. Quando si usano gli inizializzatori, le dimensioni della matrice non sono necessarie.

In questo esempio viene compilata una matrice i cui elementi sono costituiti da matrici. Ogni elemento della matrice ha una dimensione diversa.

// Declare the array of two elements.
int[][] arr = new int[2][];

// Initialize the elements.
arr[0] = [1, 3, 5, 7, 9];
arr[1] = [2, 4, 6, 8];

// Display the array elements.
for (int i = 0; i < arr.Length; i++)
{
    System.Console.Write("Element({0}): ", i);

    for (int j = 0; j < arr[i].Length; j++)
    {
        System.Console.Write("{0}{1}", arr[i][j], j == (arr[i].Length - 1) ? "" : " ");
    }
    System.Console.WriteLine();
}
/* Output:
    Element(0): 1 3 5 7 9
    Element(1): 2 4 6 8
*/

Matrici tipizzate in modo implicito

È possibile creare una matrice tipizzata in modo implicito in cui il tipo dell'istanza della matrice viene derivato tramite inferenza dagli elementi specificati nell'inizializzatore di matrice. Le regole per qualsiasi variabile tipizzata in modo implicito si applicano anche alle matrici tipizzate in modo implicito. Per altre informazioni, vedere Variabili locali tipizzate in modo implicito.

Gli esempi seguenti illustrano come creare una matrice tipizzata in modo implicito:

int[] a = new[] { 1, 10, 100, 1000 }; // int[]

// Accessing array
Console.WriteLine("First element: " + a[0]);
Console.WriteLine("Second element: " + a[1]);
Console.WriteLine("Third element: " + a[2]);
Console.WriteLine("Fourth element: " + a[3]);
/* Outputs
First element: 1
Second element: 10
Third element: 100
Fourth element: 1000
*/

var b = new[] { "hello", null, "world" }; // string[]

// Accessing elements of an array using 'string.Join' method
Console.WriteLine(string.Join(" ", b));
/* Output
hello  world
*/

// single-dimension jagged array
int[][] c =
[
    [1,2,3,4],
    [5,6,7,8]
];
// Looping through the outer array
for (int k = 0; k < c.Length; k++)
{
    // Looping through each inner array
    for (int j = 0; j < c[k].Length; j++)
    {
        // Accessing each element and printing it to the console
        Console.WriteLine($"Element at c[{k}][{j}] is: {c[k][j]}");
    }
}
/* Outputs
Element at c[0][0] is: 1
Element at c[0][1] is: 2
Element at c[0][2] is: 3
Element at c[0][3] is: 4
Element at c[1][0] is: 5
Element at c[1][1] is: 6
Element at c[1][2] is: 7
Element at c[1][3] is: 8
*/

// jagged array of strings
string[][] d =
[
    ["Luca", "Mads", "Luke", "Dinesh"],
    ["Karen", "Suma", "Frances"]
];

// Looping through the outer array
int i = 0;
foreach (var subArray in d)
{
    // Looping through each inner array
    int j = 0;
    foreach (var element in subArray)
    {
        // Accessing each element and printing it to the console
        Console.WriteLine($"Element at d[{i}][{j}] is: {element}");
        j++;
    }
    i++;
}
/* Outputs
Element at d[0][0] is: Luca
Element at d[0][1] is: Mads
Element at d[0][2] is: Luke
Element at d[0][3] is: Dinesh
Element at d[1][0] is: Karen
Element at d[1][1] is: Suma
Element at d[1][2] is: Frances
*/

Nell'esempio precedente si noti che con le matrici tipizzate in modo implicito, non vengono usate parentesi quadre sul lato sinistro dell'istruzione di inizializzazione. Inoltre, le matrici di matrici vengono inizializzate usando new [] esattamente come le matrici unidimensionali.

Quando si crea un tipo anonimo che contiene una matrice, la matrice deve essere tipizzata in modo implicito nell'inizializzatore di oggetto del tipo. Nell'esempio seguente contacts è una matrice tipizzata in modo implicito di tipi anonimi, ognuno dei quali contiene una matrice denominata PhoneNumbers. La parola chiave var non viene usata all'interno degli inizializzatori di oggetto.

var contacts = new[]
{
    new
    {
        Name = "Eugene Zabokritski",
        PhoneNumbers = new[] { "206-555-0108", "425-555-0001" }
    },
    new
    {
        Name = "Hanying Feng",
        PhoneNumbers = new[] { "650-555-0199" }
    }
};