Arrays bidimensionales
En resumen: Un array bidimensional (matriz) en Python es una lista de listas: cada elemento de la lista exterior es una fila, y los bucles anidados recorren todos los valores.
Problema
Tres semanas, tres listas
Una cafetería apunta cuántos cafés vende cada día laborable. Para una semana, la lista de la lección anterior es justo lo que necesitas. Para tres semanas haces tres listas:
week1 = [42, 38, 51, 47, 60]week2 = [45, 40, 49, 52, 63]week3 = [39, 44, 50, 48, 58]
tuesday = week1[1] + week2[1] + week3[1]print(f"Martes: {tuesday}")Martes: 122Ahora el gerente pregunta cuánto se vendió todos los martes del último año. Son 52 semanas, así que 52 listas 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 una lista que sea una tabla.
La idea
Una lista de listas: fila y columna
Una tabla en Python es una lista de listas: cada elemento de la lista exterior es una fila entera, y una fila es una lista normal de números. En Java y C# esto se llama array bidimensional, y a menudo matriz.
sales = [ [42, 38, 51, 47, 60], [45, 40, 49, 52, 63], [39, 44, 50, 48, 58],]print(sales[1][0])print(f"{len(sales)} semanas, {len(sales[0])} días")453 semanas, 5 días- Cada
[ … ]interior es una fila. Las escribimos una debajo de otra para que la tabla se vea bien. 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.len(sales)es la cantidad de filas.len(sales[0])es la longitud de la primera fila, es decir, la cantidad de columnas.
sales[1] es una fila entera, una lista 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.
sales = [ [42, 38, 51, 47, 60], [45, 40, 49, 52, 63], [39, 44, 50, 48, 58],]print(sales[1])print(sales)[45, 40, 49, 52, 63][[42, 38, 51, 47, 60], [45, 40, 49, 52, 63], [39, 44, 50, 48, 58]]Una tabla vacía de 52 × 5 llena de ceros se hace fila por fila: 52 veces añades una fila nueva de 5 ceros.
table = []for week in range(52): table.append([0] * 5)table[0][1] = 7print(len(table), len(table[0]), table[0][1], table[1][1])52 5 7 0Más precisamente, para curiosos
- Como las filas son listas separadas, pueden tener longitudes distintas. Una tabla así se llama irregular (jagged):
shifts = [ [8, 8], [6, 6, 6], [12],]print(len(shifts[1]), len(shifts[2]))3 1En ella, len(sales[0]) no es la longitud de todas las filas. Por eso en un bucle anidado es más seguro escribir len(sales[row]): la longitud de la fila que estás recorriendo en ese momento.
- No hagas la tabla vacía con
[[0] * 5] * 3. Así los tres lugares apuntan a una misma fila, como los dos nombres de una lista de la lección anterior. Un cambio en una fila se ve en todas:
table = [[0] * 5] * 3table[0][1] = 7print(table)[[0, 7, 0, 0, 0], [0, 7, 0, 0, 0], [0, 7, 0, 0, 0]]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 week in range(len(sales)): for day in range(len(sales[0])): print(f"{sales[week][day]:5}", end="") print() 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.
:5 en la f-string imprime el número en un campo de 5 caracteres de ancho, alineado a la derecha. Así las columnas quedan una debajo de otra. end="" mantiene los números en una línea, y el print() vacío después de cada fila pasa a una 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?
grades = [ [5, 3, 4, 6], [3, 4, 6, 5], [6, 2, 5, 4],]print(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 week in range(len(sales)): total = 0 for day in range(len(sales[0])): total += sales[week][day] print(f"Semana {week + 1}: {total}")Semana 1: 238Semana 2: 249Semana 3: 239sales = [ [42, 38, 51, 47, 60], [45, 40, 49, 52, 63], [39, 44, 50, 48, 58],]for week in range(len(sales)): total = 0 for day in range(len(sales[0])): total += sales[week][day] print(f"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?
days = ["Lun", "Mar", "Mié", "Jue", "Vie"]
for day in range(len(sales[0])):
total = 0
for week in range(len(sales)):
total += sales[][day]
print(f"{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 len(hall[0]) (5). len(hall) es la cantidad de filas (3), así que los dos últimos asientos de cada fila nunca se comprueban. Python no puede ver un error así: los dos son números y el programa se ejecuta.
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 la lista es la fila 0. Por eso restas 1 a los números que escribe una persona antes de usarlos como índices:
row = int(input())seat = int(input())if hall[row - 1][seat - 1] == 1: print("El asiento está ocupado.")else: hall[row - 1][seat - 1] = 1 print(f"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
IndexError, igual que con una lista normal. Es más traicionero si pide la fila 0: el índice es -1, y en Python esa es la última fila. No hay error, y se reserva el asiento equivocado:
hall = [ [1, 1, 0, 0, 1], [0, 1, 1, 1, 0], [0, 0, 0, 1, 1],]try: print(hall[7 - 1][2 - 1])except IndexError as error: print(f"IndexError: {error}")print(hall[0 - 1])IndexError: list index out of range[0, 0, 0, 1, 1]Así que comprueba los números antes de usarlos: 1 <= row <= len(hall), 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 listas: dr = [-1, 1, 0, 0] y 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 · Listas
- 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