Ir al contenido
wannacode

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];
System.out.println("Martes: " + tuesday);
Salida
Martes: 122

Ahora 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 }
};
System.out.println(sales[1][0]);
System.out.println(sales.length + " semanas, " + sales[0].length + " días");
Salida
45
3 semanas, 5 días
  • int[][] significa una tabla de números enteros. 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.length es la cantidad de filas. sales[0].length es la longitud de la primera fila, es decir, la cantidad de columnas.

En Java un array bidimensional es en realidad un array de arrays: sales[1] es una fila entera, un int[] normal con 5 números. Por eso escribes dos corchetes separados [1][0]: primero obtienes la fila, luego el número que hay en ella.

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

Como las filas son arrays separados, pueden tener longitudes distintas. Entonces dejas vacío el segundo corchete y creas cada fila tú mismo. Un array así se llama irregular (jagged):

int[][] shifts = new int[3][];
shifts[0] = new int[] { 8, 8 };
shifts[1] = new int[] { 6, 6, 6 };
shifts[2] = new int[] { 12 };
System.out.println(shifts[1].length + " " + shifts[2].length);
Salida
3 1

En un array irregular, sales[0].length no es la longitud de todas las filas. Por eso en un bucle anidado es más seguro escribir sales[row].length: la longitud de la fila que estás recorriendo en ese momento.

java.util.Arrays.deepToString(sales) devuelve toda la tabla como texto, por ejemplo [[42, 38, …], [45, 40, …]]. Es útil cuando buscas un error.

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.length; week++) {
for (int day = 0; day < sales[0].length; day++) {
System.out.printf("%5d", sales[week][day]);
}
System.out.println();
}
Salida
42 38 51 47 60
45 40 49 52 63
39 44 50 48 58

El 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.

%5d 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, println() 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 }
};
System.out.println(grades[1][2]);
Respuesta

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.length; week++) {
int total = 0;
for (int day = 0; day < sales[0].length; day++) {
total += sales[week][day];
}
System.out.println("Semana " + (week + 1) + ": " + total);
}
Salida
Semana 1: 238
Semana 2: 249
Semana 3: 239

int[][] sales = {
{ 42, 38, 51, 47, 60 },
{ 45, 40, 49, 52, 63 },
{ 39, 44, 50, 48, 58 }
};
for (int week = 0; week < sales.length; week++) {
int total = 0;
for (int day = 0; day < sales[0].length; day++) {
total += sales[week][day];
}
System.out.println("Semana " + (week + 1) + ": " + total);
}
Paso a paso, en palabras
  1. La tabla: 3 semanas (filas) de 5 días (columnas).
  2. week = 0: total vuelve a empezar desde 0.
  3. El bucle interior recorre los días: 42 + 38 + 51 + 47 + 60 = 238.
  4. Se imprime «Semana 1: 238».
  5. week = 1: total vuelve a empezar desde 0.
  6. El bucle interior recorre los días: 45 + 40 + 49 + 52 + 63 = 249.
  7. Se imprime «Semana 2: 249».
  8. week = 2: total vuelve a empezar desde 0.
  9. El bucle interior recorre los días: 39 + 44 + 50 + 48 + 58 = 239.
  10. 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[0].length; day++) {
    int total = 0;
    for (int week = 0; week < sales.length; week++) {
        total += sales[][day];
    }
    System.out.println(days[day] + ": " + total);
}

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.

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:

Scanner in = new Scanner(System.in);
int row = in.nextInt();
int seat = in.nextInt();
if (hall[row - 1][seat - 1] == 1) {
System.out.println("El asiento está ocupado.");
} else {
hall[row - 1][seat - 1] = 1;
System.out.println("Reservado: fila " + row + ", asiento " + seat);
}
Entrada
3
2
Salida
Reservado: fila 3, asiento 2
Entrada
1
2
Salida
El 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 ArrayIndexOutOfBoundsException, igual que con un array normal. Comprueba los números antes de usarlos: row >= 1 && row <= hall.length, 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.

La tabla
1 2
3 4
Salida
Diagonal principal: 5
Diagonal secundaria: 5
Primera fila: 3
Segunda fila: 7

2. 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].

La tabla
42 38 51
45 40 49
Salida
42 45
38 40
51 49

Ejercicio

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?

El laberinto
0 0 0 0
0 1 0 0
0 0 0 1
1 0 0 0
Salida
Caminos: 3
Pista

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».

El laberinto
0 0 0 0 0
1 1 1 1 0
0 0 0 0 0
0 1 1 1 1
0 0 0 0 0
Salida
Camino más corto: 16 pasos
Pista

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 (P para 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

1. ¿Qué crea new int[3][5]?
2. La tabla sales tiene 3 semanas (filas) y 5 días (columnas). ¿Qué da sales[0].length?
3. ¿Cuál es la última celda de una tabla con 3 filas y 5 columnas?
4. Quieres la suma de una columna (un día en todas las semanas). ¿Qué índice cambia en el bucle interior?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·