Matrices

Puede almacenar varias variables del mismo tipo en una estructura de datos de matriz. Puede declarar una matriz mediante la especificación del tipo de sus elementos. Si quiere que la matriz almacene elementos de cualquier tipo, puede especificar object como su tipo. En el sistema de tipos unificado de C#, todos los tipos, los predefinidos y los definidos por el usuario, los tipos de referencia y los tipos de valores, heredan directa o indirectamente de Object.

type[] arrayName;

Una matriz tiene las propiedades siguientes:

  • Una matriz puede ser unidimensional, multidimensional o escalonada.
  • El número de dimensiones se establece cuando se declara una variable de la matriz. La longitud de cada dimensión se establece cuando se crea la instancia de la matriz. No se pueden cambiar estos valores durante la vigencia de la instancia.
  • Una matriz escalonada es una matriz de matrices y cada matriz miembro tiene el valor predeterminado de null.
  • Las matrices se indexan con cero: una matriz con n elementos se indexa de 0 a n-1.
  • Los elementos de una matriz puede ser cualquier tipo, incluido un tipo de matriz.
  • Los tipos de matriz son tipos de referencia que proceden del tipo base abstracto Array. Todas las matrices implementan IList y IEnumerable. Puede usar la instrucción foreach para recorrer en iteración una matriz. Las matrices de dimensión única también implementan IList<T> y IEnumerable<T>.

Los elementos de una matriz se pueden inicializar en valores conocidos cuando se crea la matriz. A partir de C# 12, todos los tipos de colección se pueden inicializar mediante una expresión de colección. Los elementos que no se inicializan se establecen en el valor predeterminado. El valor predeterminado es el patrón de 0 bits. Todos los tipos de referencia (incluidos los tipos no anulables), tienen los valores null. Todos los tipos de valor tienen los patrones de 0 bits. Esto significa que la propiedad Nullable<T>.HasValue es false y la propiedad Nullable<T>.Value no está definida. En la implementación de .NET, la propiedad Value provoca una excepción.

Los ejemplos siguientes crean matrices unidimensionales, multidimensionales y escalonadas:

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

Matrices unidimensionales

Una matriz unidimensional es una secuencia de elementos similares. Puede acceder a un elemento a través de su índice. El índice es su posición ordinal en la secuencia. El primer elemento de la matriz está en el índice 0. Cree una matriz unidimensional mediante el operador new; para ello, especifique el tipo de elemento de matriz y el número de elementos. En el ejemplo siguiente se declaran e inicializan matrices unidimensionales:

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 primera declaración declara una matriz sin inicializar de cinco enteros, de array[0] a array[4]. Los elementos de la matriz se inicializan en el valor predeterminado del tipo de elemento, 0 para los enteros. La segunda declaración declara una matriz de cadenas e inicializa los siete valores de esa matriz. Una serie de instrucciones Console.WriteLine imprime todos los elementos de la matriz weekDay. Para matrices unidimensionales, la instrucción foreach procesa los elementos en orden creciente de índice, comenzando con el índice 0 y terminando con el índice Length - 1.

Pasar matrices unidimensionales como argumentos

Puede pasar una matriz unidimensional inicializada a un método. En el ejemplo siguiente, una matriz de cadenas se inicializa y pasa como un argumento a un método DisplayArray para cadenas. El método muestra los elementos de la matriz. A continuación, el método ChangeArray invierte los elementos de la matriz y, después, el método ChangeArrayElements modifica los tres primeros elementos de la matriz. Después de cada devolución de método, el método DisplayArray muestra que pasar una matriz por valor no impide que se cambien los elementos de la 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

Matrices multidimensionales

Las matrices pueden tener varias dimensiones. Por ejemplo, las declaraciones siguientes crean cuatro matrices: dos tienen dos dimensiones y otras dos tienen tres dimensiones. Las dos primeras declaraciones declaran la longitud de cada dimensión, pero no inicializan los valores de la matriz. Las dos segundas declaraciones usan un inicializador para establecer los valores de cada elemento de la 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

En el caso de las matrices multidimensionales, los elementos se recorren de tal manera que primero se incrementan los índices de la dimensión más a la derecha, luego la siguiente dimensión a la izquierda, y así sucesivamente hacia la izquierda. En el ejemplo siguiente se enumeran una matriz 2D y una 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

En una matriz 2D, puede considerar el índice izquierdo como la fila y el índice derecho como la columna.

En cambio, con las matrices multidimensionales, usar un bucle for anidado ofrece un mayor control sobre el orden en el que se procesan los elementos de la 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
//

Pasar matrices multidimensionales como argumentos

Pase una matriz multidimensional inicializada a un método de la misma manera que pasa una matriz unidimensional. En el código siguiente, se muestra una declaración parcial de un método de impresión que acepta una matriz bidimensional como su argumento. Puede inicializar y pasar una nueva matriz en un solo paso, como se muestra en el ejemplo siguiente. En el ejemplo siguiente, una matriz bidimensional de enteros se inicializa y pasa al método Print2DArray. El método muestra los elementos de la 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
*/

Matrices escalonadas

Una matriz escalonada es una matriz cuyos elementos son matrices, posiblemente de diferentes tamaños. Una matriz escalonada se denomina a veces "matriz de matrices". Sus elementos son tipos de referencia y se inicializan en null. En los ejemplos siguientes, se muestra cómo declarar, inicializar y acceder a matrices escalonadas. El primer ejemplo, jaggedArray, se declara en una instrucción. Cada matriz independiente se crea en instrucciones posteriores. En el segundo ejemplo, jaggedArray2, se declara e inicializa en una instrucción. Es posible mezclar matrices multidimensionales y escalonadas. El ejemplo final, jaggedArray3, es una declaración e inicialización de una matriz escalonada unidimensional que contiene tres elementos de matriz bidimensional de tamaños 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);

Los elementos de una matriz escalonada deben inicializarse para poder usarlos. Cada uno de los elementos es una matriz. También es posible usar inicializadores para rellenar los elementos de la matriz con valores. Cuando se usan inicializadores, no se necesita el tamaño de la matriz.

En este ejemplo, se crea una matriz cuyos elementos son matrices. Cada uno de los elementos de matriz tiene un tamaño 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
*/

Matrices con tipo implícito

Puede crear una matriz con tipo implícito en la que se deduce el tipo de la instancia de matriz de los elementos especificados en el inicializador de matriz. Las reglas de cualquier variable de tipo implícito también se aplican a las matrices de tipo implícito. Para más información, vea Variables locales con asignación implícita de tipos.

En los ejemplos siguientes, se muestra cómo crear una 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
*/

En el ejemplo anterior observe que, con las matrices de tipo implícito, no se usan corchetes en el lado izquierdo de la instrucción de inicialización. Tenga en cuenta también que las matrices escalonadas se inicializan mediante new [] al igual que las matrices unidimensionales.

Al crear un tipo anónimo que contiene una matriz, esta debe tener tipo implícito en el inicializador de objeto del tipo. En el ejemplo siguiente, contacts es una matriz de tipo implícito de tipos anónimos, cada uno de los cuales contiene una matriz denominada PhoneNumbers. La palabra clave var no se usa dentro de los 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" }
    }
};