Arrays bidimensionales
En resumen: Un array bidimensional (matriz) guarda valores en filas y columnas: cada elemento tiene dos índices, fila y columna, y los bucles anidados los recorren todos.
Problema
Tres semanas, tres arrays
Una cafetería apunta cuántos cafés vende cada día laborable. Para una semana, el array de la lección anterior es justo lo que necesitas. Para tres semanas haces tres arrays:
int[] week1 = { 42, 38, 51, 47, 60 };int[] week2 = { 45, 40, 49, 52, 63 };int[] week3 = { 39, 44, 50, 48, 58 };
int tuesday = week1[1] + week2[1] + week3[1];Console.WriteLine("Martes: " + tuesday);Martes: 122Ahora el gerente pregunta cuánto se vendió todos los martes del último año. Son 52 semanas, así que 52 arrays y una suma con 52 sumandos. Y un bucle no puede recorrer week1, week2, week3: son nombres distintos, no índices.
Los datos son una tabla: las semanas son filas y los días son columnas. Necesitas un array que sea una tabla.
La idea
Un array bidimensional: fila y columna
Un array en el que cada valor tiene una fila y una columna se llama array bidimensional. A menudo también se le llama matriz.
int[,] sales ={ { 42, 38, 51, 47, 60 }, { 45, 40, 49, 52, 63 }, { 39, 44, 50, 48, 58 }};Console.WriteLine(sales[1, 0]);Console.WriteLine(sales.GetLength(0) + " semanas, " + sales.GetLength(1) + " días");453 semanas, 5 díasint[,]significa una tabla de números enteros. La coma entre los corchetes dice que hay dos índices. Cada{ … }interior es una fila.sales[1, 0]es la fila con índice 1 (la segunda semana) y la columna con índice 0 (el lunes). Primero va la fila, luego la columna. Aquí también se cuenta desde 0.sales.GetLength(0)es la cantidad de filas,sales.GetLength(1)es la cantidad de columnas. El número entre paréntesis indica por qué dimensión preguntas: 0 para las filas, 1 para las columnas.
Una tabla así se llama array rectangular: todas las filas tienen la misma longitud.
Una tabla vacía se crea con sus tamaños: new int[52, 5] son 52 filas de 5 números, todos 0.
Más precisamente, para curiosos
C# también tiene un segundo tipo: el array irregular (jagged array), int[][]. Es un array de arrays, y cada fila puede tener una longitud distinta. Los índices van en corchetes separados, shifts[1][0], y la longitud de una fila es shifts[1].Length:
int[][] shifts = new int[3][];shifts[0] = new int[] { 8, 8 };shifts[1] = new int[] { 6, 6, 6 };shifts[2] = new int[] { 12 };Console.WriteLine(shifts[1].Length + " " + shifts[2].Length);3 1Usa int[,] cuando los datos son una tabla de verdad (semanas y días, filas y asientos de una sala). Usa int[][] cuando las filas tienen longitudes distintas.
sales.Length en un int[,] es la cantidad de todas las celdas (3 · 5 = 15), no la cantidad de filas. sales.Rank es la cantidad de dimensiones (2).
Míralo
Toda la tabla en la pantalla
Para pasar por cada celda necesitas dos bucles, uno dentro del otro. Los bucles anidados ya los conoces de las estrellas: el exterior elige la fila, el interior recorre las columnas de esa fila.
for (int week = 0; week < sales.GetLength(0); week++){ for (int day = 0; day < sales.GetLength(1); day++) { Console.Write($"{sales[week, day],5}"); } Console.WriteLine();} 42 38 51 47 60 45 40 49 52 63 39 44 50 48 58El bucle exterior se ejecuta 3 veces, una por cada semana. En cada una de sus vueltas, el interior se ejecuta 5 veces. 15 celdas en total, en el orden en que lees una tabla: de izquierda a derecha, de arriba abajo.
$"{x,5}" imprime el número en un campo de 5 caracteres de ancho, alineado a la derecha. Así las columnas quedan una debajo de otra. Después de cada fila, WriteLine() pasa a una línea nueva.
Pruébalo
¿Qué celda?
En el registro de notas, cada fila es un estudiante y cada columna es una asignatura.
¿Qué imprimirá el programa?
int[,] grades ={ { 5, 3, 4, 6 }, { 3, 4, 6, 5 }, { 6, 2, 5, 4 }};Console.WriteLine(grades[1, 2]);El primer índice es la fila: 1 es el segundo estudiante, { 3, 4, 6, 5 }. El segundo índice es la columna: 2 es la tercera asignatura. La nota es 6. Obtienes 2 si confundes la fila con la columna, y 3 si cuentas desde 1.
La idea
Sumas por filas y por columnas
¿Cuántos cafés se vendieron cada semana? Es la suma de cada fila. La suma empieza en 0 para cada fila nueva, por eso total está dentro del bucle exterior:
for (int week = 0; week < sales.GetLength(0); week++){ int total = 0; for (int day = 0; day < sales.GetLength(1); day++) { total += sales[week, day]; } Console.WriteLine("Semana " + (week + 1) + ": " + total);}Semana 1: 238Semana 2: 249Semana 3: 239int[,] sales ={ { 42, 38, 51, 47, 60 }, { 45, 40, 49, 52, 63 }, { 39, 44, 50, 48, 58 }};for (int week = 0; week < sales.GetLength(0); week++){ int total = 0; for (int day = 0; day < sales.GetLength(1); day++) { total += sales[week, day]; } Console.WriteLine("Semana " + (week + 1) + ": " + total);}Paso a paso, en palabras
- La tabla: 3 semanas (filas) de 5 días (columnas).
- week = 0: total vuelve a empezar desde 0.
- El bucle interior recorre los días: 42 + 38 + 51 + 47 + 60 = 238.
- Se imprime «Semana 1: 238».
- week = 1: total vuelve a empezar desde 0.
- El bucle interior recorre los días: 45 + 40 + 49 + 52 + 63 = 249.
- Se imprime «Semana 2: 249».
- week = 2: total vuelve a empezar desde 0.
- El bucle interior recorre los días: 39 + 44 + 50 + 48 + 58 = 239.
- Se imprime «Semana 3: 239».
¿Cuánto se vendió el lunes, el martes y así sucesivamente? Es la suma de cada columna. La tabla es la misma, solo cambia el orden de los bucles: el día va fuera y las semanas van dentro. Lo terminarás en la siguiente tarjeta.
Qué bucle va fuera decide qué sumas. Los índices en sales[week, day] no se mueven: la fila siempre va primero.
Pruébalo
Suma por días
El bucle exterior recorre los días, el interior recorre las semanas. ¿Qué va en el hueco?
string[] days = { "Lun", "Mar", "Mié", "Jue", "Vie" };
for (int day = 0; day < sales.GetLength(1); day++)
{
int total = 0;
for (int week = 0; week < sales.GetLength(0); week++)
{
total += sales[, day];
}
Console.WriteLine(days[day] + ": " + total);
}week. La fila es la semana, así que week va primero. El día se queda fijo mientras el bucle interior recorre las tres semanas. Para el martes sale 38 + 40 + 44 = 122, lo mismo que en la primera tarjeta, pero sin 52 nombres.
Pruébalo
Encuentra el error
La sala tiene 3 filas de 5 asientos: 1 está ocupado, 0 está libre. Hay 7 asientos libres, pero el programa dice 5. ¿En qué línea está el error?
Elige la línea con el error.
El bucle interior es para los asientos de la fila, y su cantidad es hall.GetLength(1) (5). hall.GetLength(0) es la cantidad de filas (3), así que los dos últimos asientos de cada fila nunca se comprueban. El compilador no puede ver un error así: los dos números son int.
La idea
Reserva: las personas cuentan desde 1
Un espectador quiere la fila 3, asiento 2. Para él, la primera fila es la fila 1. Para el array es la fila 0. Por eso restas 1 a los números que escribe una persona antes de usarlos como índices:
int row = int.Parse(Console.ReadLine());int seat = int.Parse(Console.ReadLine());if (hall[row - 1, seat - 1] == 1){ Console.WriteLine("El asiento está ocupado.");}else{ hall[row - 1, seat - 1] = 1; Console.WriteLine("Reservado: fila " + row + ", asiento " + seat);}32Reservado: fila 3, asiento 212El asiento está ocupado.hall es la sala de la tarjeta anterior. Una celda se cambia como una variable normal: hall[row - 1, seat - 1] = 1;.
Más precisamente, para curiosos
- Si alguien pide la fila 7, el índice 6 está fuera de la tabla y el programa se detiene con
IndexOutOfRangeException, igual que con un array normal. Comprueba los números antes de usarlos:row >= 1 && row <=hall.GetLength(0), y lo mismo para el asiento.
- Aquí cada número está en su propia línea. Cómo leer de una vez una línea entera de números (
0 1 1 0) lo verás en la próxima lección, sobre el texto.
Ejercicio
Cálculos con una tabla
Resuelve los ejercicios en tu editor. Escribe las tablas directamente en el código.
1. Diagonales y filas. Para la tabla de 2 × 2 de abajo, halla la suma de la diagonal principal (de arriba a la izquierda hasta abajo a la derecha), la de la otra diagonal y las sumas de la primera y la segunda fila. En la diagonal principal, el índice de la fila y el de la columna son iguales. En la otra diagonal, la columna es n - 1 - row.
1 23 4Diagonal principal: 5Diagonal secundaria: 5Primera fila: 3Segunda fila: 72. Gira la tabla. Las ventas están apuntadas por semanas (filas) y días (columnas). Contabilidad las quiere por días y semanas. Haz una tabla nueva en la que las filas se conviertan en columnas. Esto se llama trasponer. La tabla nueva tiene el tamaño columnas × filas, y la celda [r, c] pasa a [c, r].
42 38 51 45 40 49 42 45 38 40 51 49Ejercicio
Laberintos y tesoro
3. ¿Cuántos caminos hay? El laberinto es una tabla: 0 es un paso, 1 es una pared. Empiezas en la esquina de arriba a la izquierda y llegas a la de abajo a la derecha, moviéndote solo hacia la derecha o hacia abajo. ¿Cuántos caminos distintos hay?
0 0 0 00 1 0 00 0 0 11 0 0 0Caminos: 3Pista
Haz una segunda tabla ways del mismo tamaño. En ella escribe de cuántas maneras se llega a cada celda. A la salida se llega de 1 manera. A una pared se llega de 0 maneras. A cualquier otra celda se llega o desde arriba o desde la izquierda, así que la cantidad es la suma de la celda de arriba y la de su izquierda (si existen). Rellena la tabla fila por fila, de arriba abajo. La respuesta está en la última celda.
4. El camino más corto. Uno difícil. Ahora puedes moverte en las cuatro direcciones: arriba, abajo, izquierda y derecha. ¿Cuál es la menor cantidad de pasos para ir de la esquina de arriba a la izquierda a la de abajo a la derecha? Si no hay camino, imprime «No hay camino».
0 0 0 0 01 1 1 1 00 0 0 0 00 1 1 1 10 0 0 0 0Camino más corto: 16 pasosPista
Lanza una «ola» desde la salida. Haz una tabla dist llena de -1 (todavía no hemos llegado a esa celda) y pon 0 en la salida. Después repite: busca todas las celdas cuyo dist es igual al paso actual, y en sus vecinas libres a las que todavía no hemos llegado escribe paso + 1. La ola crece un paso en cada vuelta. Para cuando llegue a la meta o cuando no haya cambiado nada (entonces no hay camino). Las cuatro direcciones son cómodas como dos arrays: int[] dr = { -1, 1, 0, 0 }; y int[] dc = { 0, 0, -1, 1 };. La vecina en la dirección k está en la fila r + dr[k] y la columna c + dc[k].
Más ejercicios
- Encuentra el tesoro. Un juego en un mapa que es una tabla: 0 es camino, 1 es obstáculo, 2 es el tesoro. El jugador empieza en la esquina de arriba a la izquierda. En cada movimiento, imprime el mapa (
Ppara el jugador,#para un obstáculo,.para un camino) y lee una orden como número: 8 arriba, 2 abajo, 4 izquierda, 6 derecha (como en el teclado numérico). Si el movimiento lleva fuera del mapa o a un obstáculo, el jugador se queda en su sitio. Cuando pise el tesoro, imprime «¡Encontraste el tesoro en … movimientos!». - La fila con más ventas. Para la tabla
sales, halla qué semana fue la más fuerte y qué día de la semana es el más fuerte de media. - Asientos libres en una fila. Para la sala
hall, halla una fila que tenga al menos 3 asientos libres seguidos, e imprime el número de la fila y el del primer asiento.
Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: Operadores y aritmética · Condiciones · Bucles · Arrays
- Continúa en: Parámetros y return · Principios de la POO · Patrones de diseño · Grafo: lista de adyacencia y matriz
- Ejercicios sobre el tema: Fundamentos del lenguaje