trubidata
Lección 4 de 12·22 min

Listas y matrices

En esta guía (15)

Hasta ahora cada variable guardaba un solo valor. En esta lección vas a usar listas, la colección más usada de Python: una secuencia ordenada de valores que podés recorrer, modificar, ordenar y filtrar. También vas a armar matrices (listas de listas), escribir tus primeras list comprehensions y entender una trampa clásica: la diferencia entre copiar una lista y tener dos nombres para la misma.

Crear una lista

Una lista se escribe entre corchetes, con los elementos separados por comas:

python
temperaturas = [18.5, 21.0, 19.2, 24.8, 22.1]
dias = ["lunes", "martes", "miércoles"]
vacia = []
mezcla = [1, "dos", 3.0, True]

print(temperaturas)
print(len(dias))
text
[18.5, 21.0, 19.2, 24.8, 22.1]
3

Una lista puede tener elementos de cualquier tipo, incluso mezclados, aunque en la práctica casi siempre guarda elementos del mismo tipo. len() devuelve la cantidad de elementos.

Índices

Cada elemento tiene una posición, llamada índice, que empieza en 0:

python
frutas = ["manzana", "pera", "banana", "kiwi"]
#            0         1        2        3
#           -4        -3       -2       -1

print(frutas[0])    # manzana
print(frutas[2])    # banana
print(frutas[-1])   # kiwi (el último)
print(frutas[-2])   # banana (el anteúltimo)

Los índices negativos cuentan desde el final: -1 es el último elemento, sin importar cuántos haya.

Las listas son mutables: podés cambiar un elemento asignando a su índice.

python
frutas = ["manzana", "pera", "banana", "kiwi"]
frutas[1] = "durazno"
print(frutas)  # ['manzana', 'durazno', 'banana', 'kiwi']

Si pedís un índice que no existe, da error:

text
>>> frutas[10]
IndexError: list index out of range

Slicing: rebanadas de una lista

Con lista[inicio:fin] obtenés una nueva lista con los elementos desde inicio hasta fin, sin incluir fin (igual que range):

python
numeros = [10, 20, 30, 40, 50, 60]

print(numeros[1:4])   # [20, 30, 40]
print(numeros[:3])    # [10, 20, 30]  (desde el principio)
print(numeros[3:])    # [40, 50, 60]  (hasta el final)
print(numeros[-2:])   # [50, 60]      (los dos últimos)
print(numeros[::2])   # [10, 30, 50]  (de 2 en 2)
print(numeros[::-1])  # [60, 50, 40, 30, 20, 10]  (invertida)

El tercer valor es el paso, como en range. A diferencia de los índices sueltos, el slicing no da error si te pasás del largo: numeros[4:100] devuelve [50, 60].

Preguntar si algo está

El operador in devuelve True si el elemento está en la lista:

python
invitados = ["Ana", "Bruno", "Carla"]
print("Bruno" in invitados)      # True
print("Diego" in invitados)      # False
print("Diego" not in invitados)  # True

Métodos para modificar listas

Los métodos son funciones que se llaman sobre un valor con un punto: lista.metodo(...). Estos son los más usados:

python
compras = ["pan", "leche"]

compras.append("queso")          # agrega al final
print(compras)                   # ['pan', 'leche', 'queso']

compras.insert(0, "café")        # agrega en una posición
print(compras)                   # ['café', 'pan', 'leche', 'queso']

compras.extend(["arroz", "sal"]) # agrega varios al final
print(compras)                   # ['café', 'pan', 'leche', 'queso', 'arroz', 'sal']

compras.remove("leche")          # quita la primera aparición de un valor
print(compras)                   # ['café', 'pan', 'queso', 'arroz', 'sal']

ultimo = compras.pop()           # quita y devuelve el último
print(ultimo, compras)           # sal ['café', 'pan', 'queso', 'arroz']

primero = compras.pop(0)         # quita y devuelve el de esa posición
print(primero, compras)          # café ['pan', 'queso', 'arroz']

Y para buscar y contar:

python
notas = [7, 9, 4, 9, 6]
print(notas.index(9))   # 1 (posición de la primera aparición)
print(notas.count(9))   # 2 (cuántas veces aparece)

remove e index dan ValueError si el valor no está. Si no estás seguro, preguntá antes con in.

Ordenar

Hay dos formas, y la diferencia importa:

python
numeros = [5, 2, 9, 1]

ordenada = sorted(numeros)   # devuelve una lista NUEVA ordenada
print(ordenada)              # [1, 2, 5, 9]
print(numeros)               # [5, 2, 9, 1]  (la original no cambió)

numeros.sort()               # ordena la MISMA lista, no devuelve nada
print(numeros)               # [1, 2, 5, 9]

numeros.sort(reverse=True)   # de mayor a menor
print(numeros)               # [9, 5, 2, 1]

numeros.reverse()            # invierte el orden actual
print(numeros)               # [1, 2, 5, 9]
  • sorted(lista) es una función: deja la original intacta y te da una nueva.
  • lista.sort() es un método: modifica la lista y devuelve None.

Las listas de strings se ordenan alfabéticamente (con las mayúsculas antes que las minúsculas).

Funciones de resumen

python
ventas = [1200, 850, 2300, 640]
print(sum(ventas))                 # 4990
print(max(ventas))                 # 2300
print(min(ventas))                 # 640
print(sum(ventas) / len(ventas))   # 1247.5 (promedio)

sum, max y min reciben la lista entera. Con una lista vacía, max y min dan error, y el promedio dividiría por cero: chequeá antes que no esté vacía.

Recorrer una lista

Con for recorrés los elementos directamente, sin índices:

python
precios = [1500, 320, 980]
total = 0
for precio in precios:
    total += precio
print(total)  # 2800

Si además necesitás la posición, usá enumerate, que te da el índice y el elemento en cada vuelta:

python
tareas = ["lavar", "cocinar", "estudiar"]
for i, tarea in enumerate(tareas, start=1):
    print(f"{i}. {tarea}")
text
1. lavar
2. cocinar
3. estudiar

Un patrón muy común es construir una lista nueva recorriendo otra: arrancás con una lista vacía y agregás con append.

python
precios = [1500, 320, 980, 2100]
caros = []
for precio in precios:
    if precio > 1000:
        caros.append(precio)
print(caros)  # [1500, 2100]

List comprehensions

Ese patrón de "lista vacía + for + append" es tan común que Python tiene una sintaxis compacta para escribirlo, la list comprehension:

python
precios = [1500, 320, 980, 2100]

caros = [p for p in precios if p > 1000]
con_iva = [p * 1.21 for p in precios]
caros_con_iva = [round(p * 1.21) for p in precios if p > 1000]

print(caros)          # [1500, 2100]
print(con_iva)        # [1815.0, 387.2, 1185.8, 2541.0]
print(caros_con_iva)  # [1815, 2541]

Se lee así: [expresión for elemento in lista if condición], "la expresión, para cada elemento de la lista, si se cumple la condición". El if es opcional.

Con range también funciona:

python
cuadrados = [n ** 2 for n in range(1, 6)]
print(cuadrados)  # [1, 4, 9, 16, 25]

Cuándo usarlas: cuando querés armar una lista nueva transformando o filtrando otra, y la lógica entra cómoda en una línea. Cuándo no: si necesitás cortar el recorrido con break, hacer varias cosas por elemento o la línea se vuelve difícil de leer. Ahí, un for común es más claro.

Listas de listas: matrices

Un elemento de una lista puede ser otra lista. Así se representa una matriz (una tabla de filas y columnas):

python
# 3 filas x 4 columnas: ventas por sucursal (fila) y trimestre (columna)
ventas = [
    [120, 135, 150, 160],
    [ 90,  95, 110, 100],
    [200, 210, 190, 230],
]

print(ventas[0])      # [120, 135, 150, 160]  (fila 0)
print(ventas[2][3])   # 230 (fila 2, columna 3)
print(len(ventas))    # 3 filas
print(len(ventas[0])) # 4 columnas

Para recorrer todos los valores se anidan dos for:

python
ventas = [
    [120, 135, 150, 160],
    [ 90,  95, 110, 100],
    [200, 210, 190, 230],
]

for i, fila in enumerate(ventas):
    total_fila = 0
    for valor in fila:
        total_fila += valor
    print(f"Sucursal {i}: {total_fila}")
text
Sucursal 0: 565
Sucursal 1: 395
Sucursal 2: 830

El for de afuera recorre las filas; el de adentro, los valores de cada fila. (Podrías usar sum(fila), pero conviene ver el recorrido explícito una vez.)

Para totalizar por columna, recorrés con índices:

python
ventas = [
    [120, 135, 150, 160],
    [ 90,  95, 110, 100],
    [200, 210, 190, 230],
]

for col in range(len(ventas[0])):
    total_col = 0
    for fila in ventas:
        total_col += fila[col]
    print(f"Trimestre {col + 1}: {total_col}")
text
Trimestre 1: 410
Trimestre 2: 440
Trimestre 3: 450
Trimestre 4: 490

Copiar vs. referenciar

Esta es la trampa más famosa de las listas:

python
original = [1, 2, 3]
otra = original
otra.append(4)
print(original)  # [1, 2, 3, 4]

otra = original no copia la lista: crea un segundo nombre que apunta a la misma lista. Modificar una es modificar la otra. Para tener una copia independiente:

python
original = [1, 2, 3]
copia = original.copy()   # también sirve list(original) u original[:]
copia.append(4)
print(original)  # [1, 2, 3]
print(copia)     # [1, 2, 3, 4]

Con matrices hay que tener un cuidado extra: .copy() copia la lista de afuera, pero las filas siguen siendo compartidas. Y hay otra trampa al crear una matriz con *:

python
mal = [[0] * 3] * 2      # ¡las dos filas son la MISMA lista!
mal[0][0] = 9
print(mal)               # [[9, 0, 0], [9, 0, 0]]

bien = [[0] * 3 for _ in range(2)]   # cada fila es una lista nueva
bien[0][0] = 9
print(bien)              # [[9, 0, 0], [0, 0, 0]]

_ es un nombre de variable válido que, por convención, significa "no me importa este valor".

Por qué pasa esto: las variables en Python son nombres que apuntan a valores. Los números y los strings no se pueden modificar (son inmutables), así que compartirlos nunca causa sorpresas. Las listas sí se pueden modificar (son mutables), y ahí importa si dos nombres apuntan a la misma.

Errores comunes

  • Olvidar que el índice empieza en 0. El primer elemento es lista[0] y el último es lista[len(lista) - 1], o más simple, lista[-1].
  • IndexError: list index out of range: pediste una posición que no existe. Revisá el largo con len().
  • Asignar el resultado de sort(). numeros = numeros.sort() deja numeros en None. Usá numeros.sort() solo, o numeros = sorted(numeros).
  • Creer que b = a copia. Son dos nombres para la misma lista. Usá a.copy().
  • Modificar una lista mientras la recorrés (por ejemplo, hacer remove dentro de un for sobre la misma lista): se saltean elementos. Armá una lista nueva con los que querés conservar.
  • Armar una lista con for + append cuando ya hay una herramienta. Para sumar usá sum; para contar un valor, count; para filtrar, una comprehension.

Practicá

  1. Dada temps = [22.5, 25.1, 19.8, 30.2, 27.4, 18.9, 24.0] (temperaturas de una semana), mostrá la máxima, la mínima, el promedio con un decimal y cuántos días superaron el promedio.
  2. Dada la lista codigos = ["A12", "B07", "A33", "C01", "A05"], armá con una comprehension la lista de los códigos que empiezan con "A". Pista: codigo[0] es la primera letra.
  3. Dada la matriz m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], calculá la suma de la diagonal principal (1 + 5 + 9) y armá la transpuesta (filas convertidas en columnas): [[1, 4, 7], [2, 5, 8], [3, 6, 9]].
  4. Escribí un programa que pida números al usuario hasta que ingrese una línea vacía, los guarde en una lista y al final muestre la lista ordenada de menor a mayor y sin modificar la original.

Soluciones

Ejercicio 1:

python
temps = [22.5, 25.1, 19.8, 30.2, 27.4, 18.9, 24.0]

promedio = sum(temps) / len(temps)
sobre_promedio = len([t for t in temps if t > promedio])

print(f"Máxima: {max(temps)}")
print(f"Mínima: {min(temps)}")
print(f"Promedio: {promedio:.1f}")
print(f"Días sobre el promedio: {sobre_promedio}")
text
Máxima: 30.2
Mínima: 18.9
Promedio: 24.0
Días sobre el promedio: 4

Ejercicio 2:

python
codigos = ["A12", "B07", "A33", "C01", "A05"]
con_a = [c for c in codigos if c[0] == "A"]
print(con_a)  # ['A12', 'A33', 'A05']

Ejercicio 3:

python
m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

diagonal = 0
for i in range(len(m)):
    diagonal += m[i][i]
print(diagonal)  # 15

transpuesta = []
for col in range(len(m[0])):
    nueva_fila = [fila[col] for fila in m]
    transpuesta.append(nueva_fila)
print(transpuesta)  # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

En la diagonal principal, el índice de fila y el de columna coinciden: m[0][0], m[1][1], m[2][2].

Ejercicio 4:

python
numeros = []
texto = input("Número (Enter para terminar): ")
while texto != "":
    numeros.append(float(texto))
    texto = input("Número (Enter para terminar): ")

print(f"Ingresados: {numeros}")
print(f"Ordenados: {sorted(numeros)}")
text
Número (Enter para terminar): 8
Número (Enter para terminar): 3.5
Número (Enter para terminar): 10
Número (Enter para terminar): 
Ingresados: [8.0, 3.5, 10.0]
Ordenados: [3.5, 8.0, 10.0]

sorted deja numeros en el orden en que se ingresó; numeros.sort() lo hubiera cambiado.

Resumen

  • Una lista es una secuencia ordenada y mutable: [1, 2, 3]. Los índices empiezan en 0 y los negativos cuentan desde el final.
  • lista[inicio:fin:paso] devuelve una porción nueva, sin incluir fin.
  • append, insert, extend, remove y pop modifican la lista; index y count buscan.
  • sorted() devuelve una lista nueva ordenada; .sort() ordena la misma lista y devuelve None.
  • for elemento in lista recorre; enumerate agrega la posición.
  • [expr for x in lista if cond] arma una lista nueva transformando y filtrando en una línea.
  • Una matriz es una lista de listas: m[fila][columna].
  • b = a no copia: los dos nombres apuntan a la misma lista. Para copiar, a.copy().

← Volver al temario