Matrizes

Você pode armazenar diversas variáveis do mesmo tipo em uma estrutura de dados de matriz. Você pode declarar uma matriz especificando o tipo de seus elementos. Se você quiser que a matriz armazene elementos de qualquer tipo, você pode especificar object como seu tipo. No sistema de tipos unificado do C#, todos os tipos, predefinidos e definidos pelo usuário, tipos de referência e tipos de valor, herdam direta ou indiretamente de Object.

type[] arrayName;

Uma matriz tem as seguintes propriedades:

  • Uma matriz pode ser unidimensional, multidimensional ou irregular.
  • O número de dimensões é definido quando uma variável de matriz é declarada. O comprimento de cada dimensão é estabelecido quando a instância da matriz é criada. Esses valores não podem ser alterados durante o ciclo de vida da instância.
  • Uma matriz irregular é uma matriz de matrizes e cada matriz de membros tem o valor padrão de null.
  • As matrizes são indexadas por zero: uma matriz com elementos n é indexada de 0 para n-1.
  • Os elementos de matriz podem ser de qualquer tipo, inclusive um tipo de matriz.
  • Os tipos de matriz são tipos de referência derivados do tipo base abstrato Array. Todas as matrizes implementam IList e IEnumerable. Você pode usar a instrução foreach para iterar por meio de uma matriz. Matrizes unidimensionais também implementam IList<T> e IEnumerable<T>.

Os elementos de uma matriz podem ser inicializados para valores conhecidos quando a matriz é criada. A partir do C# 12, todos os tipos de coleção podem ser inicializados usando uma Expressão de coleção. Os elementos que não são inicializados são definidos como o valor padrão. O valor padrão é o padrão de 0 bits. Todos os tipos de referência (incluindo tipos não anuláveis), têm os valores null. Todos os tipos de valor têm os padrões de 0 bits. Isso significa que a propriedade Nullable<T>.HasValue é false e a propriedade Nullable<T>.Value é indefinida. Na implementação do .NET, a propriedade Value gera uma exceção.

O exemplo a seguir cria matrizes unidimensionais, multidimensionais e denteadas:

// 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];

Matrizes unidimensionais

Uma matriz unidimensional é uma sequência de elementos semelhantes. Você acessa um elemento por meio de seu índice. O índice é sua posição ordinal na sequência. O primeiro elemento na matriz está no índice 0. Você criará uma matriz unidimensional usando o novo operador que especifica o tipo de elemento de matriz e o número de elementos. O exemplo a seguir declara e inicializa matrizes unidimensionais:

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
*/

A primeira declaração declara uma matriz não inicializada de cinco inteiros, de array[0] para array[4]. Os elementos da matriz são inicializados para o valor padrão do tipo de elemento, 0 para inteiros. A segunda declaração declara uma matriz de cadeias de caracteres e inicializa todos os sete valores dessa matriz. Uma instrução foreach itera os elementos da matriz weekday e imprime todos os valores. Em matrizes unidimensionais, a instrução foreach processa elementos em ordem crescente de índice, começando com o índice 0 e terminando com índice Length - 1.

Passar matrizes unidimensionais como argumentos

É possível passar uma matriz unidimensional inicializada para um método. No exemplo a seguir, uma matriz de cadeia de caracteres é inicializada e passada como um argumento para um método DisplayArray para cadeias de caracteres. O método exibe os elementos da matriz. Em seguida, o método ChangeArray inverte os elementos da matriz, e o método ChangeArrayElements modifica os três primeiros elementos da matriz. Depois que cada método retorna, o método DisplayArray mostra que passar uma matriz por valor não impede alterações nos elementos da matriz.

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

Matrizes multidimensionais

As matrizes podem ter mais de uma dimensão. Por exemplo, as seguintes declarações criam quatro matrizes: duas têm duas dimensões, duas têm três dimensões. As duas primeiras declarações declaram o comprimento de cada dimensão, mas não inicializam os valores da matriz. As duas segundas declarações usam um inicializador para definir os valores de cada elemento na matriz multidimensional.

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

Em matrizes multidimensionais, os elementos são percorridos de modo a que os índices da dimensão mais à direita sejam aumentados primeiro e, em seguida, da próxima dimensão à esquerda, e assim por diante seguindo para a esquerda. O exemplo a seguir enumera uma matriz 2D e 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

Em uma matriz 2D, você pode pensar no índice esquerdo como a linha e o índice direito como a coluna.

No entanto, com matrizes multidimensionais, usar um loop aninhado for oferece mais controle sobre a ordem na qual processar os elementos da matriz:

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
//

Passar matrizes multidimensionais como argumentos

Você passa uma matriz multidimensional inicializada para um método da mesma forma que você passa uma matriz unidimensional. O código a seguir mostra uma declaração parcial de um método de impressão que aceita uma matriz bidimensional como seu argumento. É possível inicializar e passar uma nova matriz em uma etapa, conforme mostrado no exemplo a seguir. No exemplo a seguir, uma matriz bidimensional de inteiros é inicializada e passada para o método Print2DArray. O método exibe os elementos da matriz.

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
*/

Matrizes denteadas

Uma matriz irregular é uma matriz cujos elementos são matrizes, possivelmente de tamanhos diferentes. Às vezes, uma matriz denteada é chamada de uma "matriz de matrizes." Seus elementos são tipos de referência e são inicializados para null. Os exemplos a seguir mostram como declarar, inicializar e acessar matrizes denteadas. No primeiro exemplo, jaggedArray é declarado em uma instrução. Cada matriz contida é criada em instruções subsequentes. No segundo exemplo, jaggedArray2 é declarado e inicializado em uma instrução. É possível misturar matrizes irregulares e multidimensionais. No exemplo final, jaggedArray3 é uma declaração e inicialização de uma matriz irregular unidimensional que contém três elementos de matriz bidimensional de tamanhos diferentes.

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);

Os elementos de uma matriz irregular devem ser inicializados antes que você possa usá-los. Cada um dos elementos é uma matriz. Também é possível usar inicializadores para preencher os elementos da matriz com valores. Ao usar inicializadores, você não precisa do tamanho da matriz.

Este exemplo cria uma matriz cujos elementos são matrizes. Cada um dos elementos da matriz tem um tamanho diferente.

// 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
*/

Matrizes de tipo implícito

É possível criar uma matriz de tipo implícito na qual o tipo da instância da matriz é inferido com base nos elementos especificados no inicializador de matriz. As regras para qualquer variável de tipo implícito também se aplicam a matrizes de tipo implícito. Para obter mais informações, consulte Variáveis locais de tipo implícito.

Os exemplos a seguir mostram como criar uma matriz de tipo implícito:

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
*/

No exemplo anterior, observe que, com as matrizes de tipo implícito, não são usados colchetes do lado esquerdo da instrução de inicialização. Observe também que as matrizes denteadas são inicializadas usando new [] assim como matrizes unidimensionais.

Ao criar um tipo anônimo que contém uma matriz, ela deve ser de tipo implícito no inicializador de objeto do tipo. No exemplo a seguir, contacts é uma matriz de tipo implícito de tipos anônimos, cada um contém uma matriz denominada PhoneNumbers. A palavra-chave var não é usada dentro dos inicializadores de objeto.

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