Pensamiento Computacional · Unidad 4 — Estructuras de datos
Tuplas
Una tupla es una lista que no se puede modificar. Sirve justamente para eso: dejar claro que ese conjunto de datos no cambia.
La explicación
Van con paréntesis
punto[0] → 3
len(punto) → 2
Se indexa y se recorre igual que una lista. La única diferencia es que
punto[0] = 9 da error: las tuplas son inmutables.
Para qué sirve algo que no se puede cambiar
Como regla: lista para una colección de cosas del mismo tipo que puede crecer (las notas de un curso), tupla para un dato con partes fijas (un par de coordenadas).
Empaquetar y desempaquetar
x, y = punto # desempaquetar: x vale 3, y vale 5
Esto ya lo venís usando sin saberlo. Cuando una función hace
return a // b, a % b está devolviendo una tupla, y
c, r = dividir(7, 2) la está desempaquetando.
De ahí también sale el intercambio en una línea del tema 2.1:
La derecha arma la tupla (b, a) y la izquierda la desempaqueta. Por eso no hace
falta variable auxiliar: la tupla la hace de intermediaria.
Una tupla de un solo elemento
t = (5,) → esto sí es una tupla de un elemento
La coma es lo que hace la tupla, no el paréntesis. Es una rareza de Python que conviene conocer porque el error que produce es desconcertante.
Convertir
tuple([1, 2, 3]) → (1, 2, 3)
Para qué se usan de verdad: devolver más de un valor
Éste es el uso que aparece en cada programa un poco largo, y casi nunca se lo presenta como «tupla»:
return min(xs), max(xs)
r = extremos([4, 8, 15, 16, 23, 42]) → (4, 42)
mn, mx = extremos([4, 8, 15, 16, 23, 42]) → mn = 4, mx = 42
Una función devuelve un valor, siempre. Lo que pasa con return a, b es que ese único valor es una tupla, y el desempaquetado del otro lado la reparte. Por eso conviene tener el tema claro aunque nunca escribas un paréntesis a propósito: lo estás usando igual.
Lo que una lista no puede hacer
Al no poder cambiar, una tupla sirve de clave de diccionario y una lista no. Los diccionarios recién se ven en el tema que sigue, el 4.5: mirá esto de reojo y quedate con la idea de que una clave tiene que ser algo que no pueda cambiar a mitad de camino.
d = {[0, 0]: "origen"} → TypeError: unhashable type: 'list'
t[1].append(4) → t ahora es (1, [2, 3, 4])
t[0] = 9 → TypeError: 'tuple' object does not support item assignment
Una función tiene que recibir una lista de puntos (x, y) y devolver cuántos están en el primer cuadrante (los dos valores positivos).
Cada punto es una tupla, así que se puede desempaquetar directamente en el
for:
cuenta = 0
for x, y in puntos:
if x > 0 and y > 0:
cuenta = cuenta + 1
return cuenta
Con [(1, 2), (-3, 4), (5, 6)]: el primero cuenta, el segundo no
(x es negativo), el tercero sí. Devuelve 2.
for x, y in puntos. En cada vuelta agarra una tupla y la
desempaqueta sola en dos variables. La alternativa sería
for p in puntos: y después usar p[0] y p[1], que
funciona igual pero se lee mucho peor: x e y dicen qué son,
p[0] no.
Por qué tupla y no lista para cada punto. Un punto tiene exactamente dos coordenadas y
no va a crecer. La tupla deja eso escrito, y de paso evita que alguien le haga
append por error.
Control: probá con un punto en el eje, como (0, 5). Con
> no cuenta, que es lo correcto: el origen y los ejes no son parte de ningún
cuadrante.
return:
dentro, ejes = contar(puntos). No hace falta ninguna
estructura nueva: return a, b arma una tupla y el desempaquetado la reparte en dos
variables con nombre.
El control que cierra la variante: los dos números tienen que sumar el total de puntos
de la lista. Si suman de menos, hay un punto que no entró en ninguna de las dos ramas — casi
siempre por haber usado > en un lado y >= en el otro.
Una función recibe una lista de tuplas (nombre, nota) y tiene que devolver el nombre del mejor alumno y la lista de los desaprobados (nota menor a 4), ordenada alfabéticamente. Tiene que funcionar con la lista vacía.
La ventaja de recorrer tuplas: se pueden desarmar en el propio for, y el código queda legible sin índices.
...
Eso es mucho más claro que alumno[0] y alumno[1], y evita el error de cruzar los índices, que con tuplas de tres o cuatro elementos es casi seguro.
La función completa:
mejor = None
desaprobados = []
for nombre, nota in alumnos:
if mejor is None or nota > mejor[1]:
mejor = (nombre, nota)
if nota < 4:
desaprobados.append(nombre)
return (mejor[0] if mejor else None, sorted(desaprobados))
Un solo recorrido para las dos cosas. Se podría hacer en dos ciclos, uno para el mejor y otro para los desaprobados, y estaría bien; en uno solo se lee mejor y se recorre la mitad.
El mejor guarda la tupla entera, no solo el nombre, porque hace falta la nota para comparar en la vuelta siguiente. Recién al final se devuelve el nombre.
El > estricto decide los empates. Con nota > mejor[1], si dos alumnos tienen la misma nota máxima gana el que aparece primero en la lista. Con >= ganaría el último. Las dos son defendibles; lo que hay que hacer es elegir a propósito y decirlo.
El sorted(desaprobados) del final ordena alfabéticamente y devuelve una lista nueva. Con .sort() también se ordena, pero devuelve None, y usarlo dentro de un return es uno de los errores más frecuentes:
return lista.sort() → devuelve None ✗
Las pruebas:
→ ("Caro", ["Beto", "Dani"])
[("Ana", 9), ("Beto", 9)] → ("Ana", []) empate: gana el primero
El caso de la lista vacía es el que rompe si no se protege: mejor queda en None y mejor[0] tira un error. El if mejor else None del return lo resuelve en una línea.
Un control rápido: Beto y Dani están ordenados alfabéticamente aunque en la lista original Beto venía antes que Dani por casualidad. Conviene probar con datos donde el orden original y el alfabético no coincidan —por ejemplo poniendo a Dani primero— para que el sorted se note.
Dónde se pierde el punto: comparar contra mejor en vez de contra mejor[1]. Comparar una nota con una tupla tira un error en Python 3; en otros lenguajes compararía cualquier cosa y devolvería un resultado sin sentido.
Dónde se cae la mayoría
- Intentar modificar una tupla. No se puede: hay que convertirla a lista o armar una nueva.
- Escribir (5) creyendo que es una tupla de un elemento. Falta la coma: (5,).
- Usar tupla donde la colección va a crecer. Si hay que agregar elementos, va lista.
Hasta acá la explicación. La práctica es la otra mitad: 8 ejercicios de este tema, en cuatro niveles, que no te dicen sólo si está bien al final sino que te corrigen en cada paso y te explican por qué. Y uno para escribir el programa vos, que se prueba ejecutándolo en Python ahí mismo, en el navegador. Además trae una animación que muestra la idea en movimiento.
Practicar Tuplas →Dónde entra este tema en el parcial
- Primer parcial — Completar: armar una lista nueva20 puntos · resuelto paso a paso
Los otros temas de la unidad 4
Estructuras de datos