Matrices.

Hasta ahora hemos hecho uso de variables para contener cada una de ellas un único valor. Por ejemplo, variables declaradas de tipoo 'int' para enteros, o variables declaradas de tipo 'string' para cadenas de caracteres. Sin embargo, será muy necesario manejar a través de variables conjuntos de datos muy extensos en lugar de un único valor. Por ejemplo, para calcular la temperatura media del caluroso mes de agosto, será necesario poseer los valores de la temperatura de, al menos, 31 días, es decir, un valor por cada uno de los días del mes de agosto; ello nos obligaría a declarar y usar 31 variables diferentes, lo cual ya sería un trabajo importante. Pero ahora imaginemos que deseamos calcular la temperatura media de todo un año: ¡ tendríamos que inicializar 365 variables diferentes!, opción descartada automáticamente.

Las matrices son la forma más económica de registrar conjuntos de valores, eso sí, todos y cada uno de ellos del mismo tipo ('double', 'int', 'string', 'long', 'bool', etc.). Así pues, una matriz es un conjunto de elementos del mismo tipo almacenados en la memoria de manera consecutiva. Cada elemento puede ser accedido por su nombre seguido de uno o más índices encerrados entre corchetes ([]). De momento nos centraremos en las matrices de un sólo índice, también llamadas matrices unidimensionales.

Matrices unidimensionales.

Imagina que tenemos una matriz unidimensional llamada 'temper' que va a contener los datos de temperatura del mes de agosto. Por lo tanto, debería tener una profundidad de 31 elementos, que serían los siguietnes: 'temper[0]', 'temper[1]', 'temper[2]', ..., 'temper[29] y 'temper[30]'. Observa que el último elemento de la matriz es 'temper[30]' y no 'temper[31]'. ¿Por qué? Porque hemos empezado erstableciendo el primer elemento como 'temper[0]', por lo que la cuenta comienza con el índice 0 y termina en el índice 31. Esto es muy importante, porque el primer índice de una matriz siempre es el índice 0.

int[] temp = new int[31];

En la declaración de nuestra variable, indicamos que va a ser de tipo 'int'. Seguimos con los corchstes para indicar al compilador que se trata de una matriz y la creamso a través de la palabra clave 'new'. A continuación especificamos que la matriz será unidimensional (un solo índice) y que su profundidad será de 31 elementos. Vuelvo a arecordarte que, aunque le digamos al compilador que la profundidad será de 31 elementos, el primer índice será el 0 y el último el 30. Ten esto siempre en cuenta, pues serán muchas las veces que el compilador te mostrará errores derivados de hacer uso de índices de matriz que sobrepasan lo inicializado.

int[] temp = new int[31];
temp[0] = 33;
temp[1] = 35;
temp[2] = 37;
temp[29] = 28;
// ...
temp[30] = 27;

Ahora hemos procedido a asignar valores a los diferentes elementos de la matriz para su posterior cálculo. Más adelante verás que la asignación de valores a los elementos de una matriz se llevan a cabo, por ejemplo, a través de bucles 'for', asignando determinados valores de una manera extremadamente rápida y económica en función de otros algoritmos asociados al propósito de la existencia de la matriz.

Matrices multidimensionales.

Evidentemente, si aún no has comprendido bien las matrices unidimensionales, ahora es el momento de volver hacia arriba y repasar lo visto hasta ahora. Las matrices multidimensionales no deben asustarnos por su nombre. Es lo mismo, pero pensando en más de una dimensión. Pensa en una matriz unidimensional como si sus elementos estuvieran distribuidos a lo largo de una línea recta; ahora piensa en, por ejemplo, una matriz bidimensional, en la que sus elementos están distribuidos en dos dimensiones, largo y ancho, formando un diagrama cartesiano, el cual tendrá corrdenadas establecidas por sus dos dimensiones. Aplica la misma idea a una matriz tridimensional, en la cual tenenmos sus elementos distribuidos a lo largo de las dimensiones largo, alto y ancho, y piensa en una disposición espacial de tres dimensiones, tal y como vemos el mundo actual. Y así sucesivamente, aunque ya sé que con más de cuatro dimensiones, (la cuarta es el tiempo) la cosa se complica para mentes no tan avanzadas como la mía.

Para que no te marees con tanta dimensíón, vamos a empezar por las matrices bidimensionales, es decir, aquellas matrices que tendrán no un índice, sino dos.

int[,] number = new int[3, 2];
number[0,0] = 1;
number[0,1] = 2;
number[1,0] = 3;
number[1,1] = 4;
number[2,0] = 5;
number[2,1] = 6;

La matriz 'number' ha sido definida de tipo 'int' y de dos dimensiones. Una primera dimensión de profundidad 3 y una segunda dimensión de profundidad 2. Por lo tanto, los índices de la primera dimensión serán 0, 1 y 2, y los índices de la segunda dimensión serán 0 y 1. Por lo tanto, el número total de distintos valores que podamos almacenar en la matriz 'number' será un total de 6. Los valores de la profundidad de cadá dimensión han sido declarados mediante un número entero, pero también pueden ser declarados de manera indirecta mediante el uso de variables:

int firstIndex = 3;
int secondIndex = 2;
int[,] number = new int[firstIndex, secondIndex];
number[0,0] = 1;
number[0,1] = 2;
number[1,0] = 3;
number[1,1] = 4;
number[2,0] = 5;
number[2,1] = 6;

Ahora utilicemos un bucle 'for' para la inicialización de los valores de la matriz:

int firstIndex = 3;
int secondIndex = 2;
int[,] number = new int[firstIndex, secondIndex];
int counter = 0;
for (int i = 0; i < firstIndex; i++)
{
    for (int j = 0; j < secondIndex; j++)
    {
        number[i, j] = counter;
        counter++;
    }
}

Hasta la declaración de la matriz, todo igual que antes. Pero ahora declaramos una variable 'counter' que será la encargada de asignar el valor a cada uno de los elementos de la matriz. Establecemos dos bubles 'for' cuya tarea será la de ir recorriendo todas las dimenbsiones de la matriz, primero en su primera dimensión y luego en su segunda dimensión, y volcando el valor de 'counter' en cada uno de los elementos de la matriz según los valores de las variables 'i' y 'j'. Al final de cada bucle se suma una unidad al valor de 'counter' para que dicho valor sea distinto para cada elemento de la matriz. El resultado de toda esta secuencia será el mismo que en el ejemplo anterior en el que asignábamos manualmente los valores a los elementos de la matriz, pero ahora esa asignación se realiza de manera automática.

Por extensión de todo lo visto hasta ahora con matrices, podemos declarar matrices multidimensionales como las siguientes:

float[,,,] matrix1 = new float[1342, 233, 5543, 45542];
string[,] matrix2 = new string[400, 45];

Ahora 'matrix1' es una matriz de tipo 'float' de cuatro dimensiones, y 'matrix2' es una matriz de tipo 'string' de dos dimensiones, ambas con profundidades bastante elevadas. Concretamente, 'matrix1' tendrá un total de nada más y nada menos que 78.934.236.835.916 (¡más de 78 mil millones!) de elementos, una proporción que, naturalmente, será difícil que llegues a manejar alguna vez en tus aplicaciones. Para casos tan particulares, y teniendo en cuenta el alto coste de uso de memoria con matrices de estas caracterísicas, hay otros tipos de elementos en C#, como las colecciones, que resultan más apropiadas y fáciles de manejar. Un ejemplo: una matyriz tridimensional de profundidad 256*256*256 tiene un elevado coste en memoria, pues necesita 67.108.864 bytes de memoria (67,1 MB.).

Otra manera muy común de asignación de valores a los elementos de una matriz es la siguiente:

int[] matrix = new int[] { 2, 3, 4 };

Hemos declarado una matriz unidimensional de tipo 'int' con profundidad de 3 elementos, a los cuales les hemos asignado los valores 2, 3, y 4. Es lo mismo que lo siguiente:

int[] matrix = new int[3];
matrix[0] = 2;
matrix[1] = 3;
matrix[2] = 4;

Pero nos habíamos ahorrado tres líneas de código fuente, ya que en la primera expresión hemos matado dos pájaros de un tiro: hemos declarado la matriz y, al mismo tiempo, hemos asignado valores a sus tres elementos.