Hola! Ahora guardamos muchas cosas juntas
En el capítulo 3 cada variable guardaba un solo valor. Eso alcanza para aprender y no alcanza para trabajar 🙂
En un archivo real tienes tres mil ventas, no una. Así que necesitas estructuras que guarden muchas cosas, y en Python son tres las que vas a usar todo el tiempo.
Antes de la tabla, piensa en el último archivo que abriste: ¿qué guardaba cada fila, una cosa sola o varias con nombre? Según cómo contestes eso, la estructura que necesitas ya está elegida 🙂
| Estructura | Se escribe | Se puede cambiar | Para qué |
|---|---|---|---|
| Lista | [1, 2, 3] | Sí | Lo que sea que tenga orden y vaya cambiando |
| Tupla | (1, 2, 3) | No | Cosas que no deben cambiar: coordenadas, una fila fija |
| Diccionario | {'ciudad': 'Lima'} | Sí | Datos con nombre. Es como llega cualquier API |
Listas: lo que más vas a usar
ciudades = ['Lima', 'Arequipa', 'Cusco', 'Piura', 'Trujillo'] print(ciudades[0]) print(ciudades[2]) print(len(ciudades))
Lima Cusco 5
Se cuenta desde cero. Ya lo vimos en el capítulo 2 con el
IndexError, y te lo repito porque es la fuente número uno de
errores por uno de diferencia.
Ahora el atajo que te evita hacer cuentas: los índices negativos.
print(ciudades[-1]) # la ultima, siempre print(ciudades[-2]) # la penultima
Trujillo Piura
Nunca más ciudades[len(ciudades) - 1]. Yo escribí esa
monstruosidad durante meses antes de que alguien me enseñara el -1 😅
Rebanadas, que es como se corta una lista
Los dos puntos dentro de los corchetes sacan un pedazo:
print(ciudades[0:3]) # de la 0 hasta ANTES de la 3 print(ciudades[:3]) # lo mismo, el 0 se sobreentiende print(ciudades[2:]) # de la 2 hasta el final print(ciudades[-2:]) # las dos ultimas print(ciudades[::2]) # de dos en dos
['Lima', 'Arequipa', 'Cusco'] ['Lima', 'Arequipa', 'Cusco'] ['Cusco', 'Piura', 'Trujillo'] ['Piura', 'Trujillo'] ['Lima', 'Cusco', 'Trujillo']
El límite de la derecha no se incluye. Eso confunde al
principio y tiene una gracia: ciudades[0:3] te da exactamente 3
elementos, y ciudades[:3] + ciudades[3:] te devuelve la lista
entera sin repetir ni perder nada.
Y una que parece un truco de fiesta y sirve de verdad:
print(ciudades[::-1])
['Trujillo', 'Piura', 'Cusco', 'Arequipa', 'Lima']
Modificar una lista
ventas = [480.37, 524.90, 154.83] ventas.append(2480.84) # agrega al final ventas.insert(0, 100.0) # inserta en una posicion print(ventas) ultimo = ventas.pop() # saca el ultimo Y te lo devuelve print(ultimo, ventas) ventas.remove(154.83) # quita por valor, no por posicion print(ventas)
[100.0, 480.37, 524.9, 154.83, 2480.84] 2480.84 [100.0, 480.37, 524.9, 154.83] [100.0, 480.37, 524.9]
Ojo con remove: quita la primera aparición del
valor, no todas. Y si el valor no está, revienta.
ventas.remove(999)
ValueError: list.remove(x): x not in list
Ordenar, y el error que da la primera vez
Hay dos formas de ordenar y confundirlas te deja con una variable vacía.
montos = [480.37, 154.83, 2480.84, 524.90] ordenados = sorted(montos) # devuelve una lista nueva print(ordenados) print(montos) # la original no se toco
[154.83, 480.37, 524.9, 2480.84] [480.37, 154.83, 2480.84, 524.9]
montos.sort() # ordena la original y devuelve None print(montos)
[154.83, 480.37, 524.9, 2480.84]
Y aquí el error clásico, que quiero que veas de frente:
resultado = montos.sort()
print(resultado)
None
Sí: None. Porque .sort() ordena la lista en el sitio
y no devuelve nada. Si guardas su resultado, guardas la nada 🙃
La regla para acordarte: sorted() te da una lista nueva,
.sort() modifica la que ya tienes. Cuando dudes, usa
sorted(), que es más difícil de romper.
print(sorted(montos, reverse=True)) print(sorted(['Cusco', 'arequipa', 'Lima'], key=str.lower))
[2480.84, 524.9, 480.37, 154.83] ['arequipa', 'Cusco', 'Lima']
Ese key=str.lower es lo que evita que las mayúsculas se ordenen
antes que todas las minúsculas, que es lo que pasa por defecto.
La copia que no se copió
Presta atención a esto, que es el error más traicionero del principio y no falla: te da un resultado equivocado sin decir nada.
original = [1, 2, 3] copia = original # esto NO es una copia copia.append(4) print('copia :', copia) print('original:', original)
copia : [1, 2, 3, 4] original: [1, 2, 3, 4]
Se modificaron las dos 😱
Acuérdate del capítulo 3: una variable es una etiqueta, no una caja. Con
copia = original le pegaste una segunda etiqueta a la
misma lista. No hay dos listas, hay una con dos nombres.
Se comprueba así:
print(copia is original)
True
Para copiar de verdad hay tres formas, y las tres valen:
original = [1, 2, 3] copia_a = original.copy() copia_b = list(original) copia_c = original[:] # una rebanada completa copia_a.append(99) print(original, copia_a) print(copia_a is original)
[1, 2, 3] [1, 2, 3, 99] False
Con esto te ahorro una tarde de "pero si yo no toqué esa variable". A mí me pasó con un dataframe y perdí medio día buscando el fantasma 👻
Tuplas: las que no se pueden cambiar
Una tupla es una lista que no se puede modificar. Se escribe con paréntesis.
coordenada = (-12.0464, -77.0428) # Lima print(coordenada[0]) coordenada[0] = 0
TypeError: 'tuple' object does not support item assignment
¿Y para qué querría algo que no puedo cambiar? Por tres razones muy concretas:
- 🔒 Dice "esto no se toca". Un par de coordenadas, un rango de fechas fijo.
- 🗝️ Puede ser clave de un diccionario. Una lista no puede.
- 📦 Es lo que devuelve una función cuando devuelve varias cosas.
Ese último punto lo vas a ver todo el tiempo:
def minimo_y_maximo(numeros): return min(numeros), max(numeros) bajo, alto = minimo_y_maximo([480.37, 154.83, 2480.84]) print(bajo, alto)
154.83 2480.84
Eso de repartir una tupla en varias variables se llama desempaquetado y es puro Python. Lo vamos a usar mucho en el capítulo 6.
Diccionarios: datos con nombre
Aquí está la estructura que más te va a servir en datos, porque es como llega la información del mundo real.
venta = {
'cliente': 'C0045',
'ciudad': 'Trujillo',
'canal': 'Marketplace',
'monto': 480.37,
'unidades': 10,
}
print(venta['ciudad'])
print(venta['monto'] * 1.18)
Trujillo 566.8366
Ya no dependes de recordar que la ciudad estaba en la posición 1. Pides por nombre, que es como piensa una persona.
get, que evita que reviente
print(venta['descuento'])
KeyError: 'descuento'
Con corchetes, si la clave no existe, se cae. Con .get() te
devuelve None, o lo que tú digas:
print(venta.get('descuento')) print(venta.get('descuento', 0))
None 0
Ese segundo caso es oro puro cuando procesas datos que a veces traen un campo y a veces no, que es siempre 🌸
Recorrer un diccionario
for clave in venta: print(clave)
cliente ciudad canal monto unidades
for clave, valor in venta.items(): print(f'{clave:10} {valor}')
cliente C0045 ciudad Trujillo canal Marketplace monto 480.37 unidades 10
.items() es el que vas a usar el 90% de las veces. Los otros dos
son .keys() y .values(), y se llaman igual de fácil.
Lo que de verdad te va a llegar: una lista de diccionarios
Junta las dos estructuras y tienes la forma en que viene cualquier respuesta de una API, cualquier JSON, cualquier exportación de un sistema.
ventas = [
{'ciudad': 'Lima', 'canal': 'Web', 'monto': 480.37},
{'ciudad': 'Cusco', 'canal': 'Tienda', 'monto': 154.83},
{'ciudad': 'Lima', 'canal': 'WhatsApp', 'monto': 2480.84},
{'ciudad': 'Piura', 'canal': 'Web', 'monto': 524.90},
]
total = 0
for v in ventas:
total = total + v['monto']
print(f'Total: S/{total:,.2f}')
print(f'Ticket promedio: S/{total / len(ventas):,.2f}')
Total: S/3,640.94 Ticket promedio: S/910.24
Y ahora agrupemos por ciudad, que es la operación que más veces vas a hacer en tu vida con datos:
por_ciudad = {}
for v in ventas:
ciudad = v['ciudad']
por_ciudad[ciudad] = por_ciudad.get(ciudad, 0) + v['monto']
print(por_ciudad)
{'Lima': 2961.21, 'Cusco': 154.83, 'Piura': 524.9}
Guárdate ese patrón, que es un clásico: diccionario.get(clave, 0) +
algo. La primera vez que aparece una ciudad, .get devuelve 0
y arranca la suma; las siguientes, sigue sumando.
En el capítulo 12 esto mismo se escribe así: df.groupby('ciudad')
['monto'].sum(). Una línea. Pero quería que vieras primero lo que hay
por debajo, porque el día que groupby haga algo raro vas a saber
qué está pasando 💜
Comprensiones de lista
Esta es la forma corta de crear una lista a partir de otra, y es tan de Python que se nota cuando alguien no la usa.
montos = [480.37, 154.83, 2480.84, 524.90] # La forma larga con_igv = [] for m in montos: con_igv.append(round(m * 1.18, 2)) # La forma de Python con_igv_corto = [round(m * 1.18, 2) for m in montos] print(con_igv) print(con_igv == con_igv_corto)
[566.84, 182.7, 2927.39, 619.38] True
Se lee de izquierda a derecha casi como una frase: "redondea eme por 1,18, para cada eme en montos".
Y se le puede poner una condición al final:
grandes = [m for m in montos if m > 500] print(grandes) ciudades = ['Lima', 'cusco', 'AREQUIPA'] print([c.title() for c in ciudades])
[2480.84, 524.9] ['Lima', 'Cusco', 'Arequipa']
Un consejo de alguien que se pasó de lista: si tu comprensión no cabe en dos líneas, escríbela como bucle normal. La gracia es que se lea mejor, no que sea más corta.
Conjuntos: para preguntar quién está y quién no
Hay una cuarta estructura que casi nunca sale en los tutoriales y que resuelve en una línea preguntas que con listas ocupan diez 🎯
Un conjunto es una bolsa sin repetidos y sin orden. Se escribe con llaves, como el diccionario, pero sin dos puntos.
enero = ['C0045', 'C0325', 'C0260', 'C0111', 'C0045'] febrero = ['C0325', 'C0777', 'C0045', 'C0888'] clientes_enero = set(enero) clientes_febrero = set(febrero) print('compras de enero :', len(enero)) print('clientes distintos :', len(clientes_enero)) print('compraron los dos meses:', sorted(clientes_enero & clientes_febrero)) print('solo enero, se fueron :', sorted(clientes_enero - clientes_febrero)) print('solo febrero, nuevos :', sorted(clientes_febrero - clientes_enero)) print('distintos en total :', len(clientes_enero | clientes_febrero))
compras de enero : 5 clientes distintos : 4 compraron los dos meses: ['C0045', 'C0325'] solo enero, se fueron : ['C0111', 'C0260'] solo febrero, nuevos : ['C0777', 'C0888'] distintos en total : 6
Eso es un análisis de retención entero en seis líneas 💜
- 🤝
&es los que están en los dos: se quedaron. - ➖
-es los que están en el primero y no en el segundo: se fueron. Ojo al orden, que aquí sí importa. - ➕
|es todos, sin repetir.
Y la otra cosa para la que sirven: preguntar si algo está dentro. En una lista larga, Python va mirando uno por uno; en un conjunto va directo, sin recorrer nada.
print('C0045 compro en enero:', 'C0045' in clientes_enero) print('C0999 compro en enero:', 'C0999' in clientes_enero)
C0045 compro en enero: True C0999 compro en enero: False
Con cinco clientes da igual. Con doscientos mil, la lista tarda y el conjunto
no. Si vas a preguntar in muchas veces sobre lo mismo, conviértelo a
conjunto una vez y pregunta ahí 🏃♀️
Lo que un conjunto no tiene es orden, y eso es literal:
clientes_enero[0]
TypeError: 'set' object is not subscriptable
No hay primero. No hay posición. Si necesitas verlos ordenados, pásalo por
sorted() como hice arriba, y si necesitas conservar el orden en que
llegaron, entonces lo que querías era una lista 📋
Contar y agrupar sin escribir el bucle a mano
El ejercicio de contar por categoría lo hiciste con un diccionario y un
get. Funciona perfecto y hay dos herramientas que lo dejan en una
línea, las dos en el módulo collections 🧰
from collections import Counter, defaultdict movimientos = [ {'ciudad': 'Lima', 'categoria': 'Abarrotes', 'monto': 480.37}, {'ciudad': 'Arequipa', 'categoria': 'Bebidas', 'monto': 154.83}, {'ciudad': 'Lima', 'categoria': 'Abarrotes', 'monto': 2480.84}, {'ciudad': 'Cusco', 'categoria': 'Limpieza', 'monto': 524.90}, {'ciudad': 'Lima', 'categoria': 'Bebidas', 'monto': 890.00}, ] cuenta = Counter(v['ciudad'] for v in movimientos) print(cuenta) print('la que mas vende:', cuenta.most_common(1)) print('cuantas de Piura:', cuenta['Piura'])
Counter({'Lima': 3, 'Arequipa': 1, 'Cusco': 1})
la que mas vende: [('Lima', 3)]
cuantas de Piura: 0
Tres regalos ahí 🎁
Counter cuenta lo que le pases y ya viene ordenado de mayor a
menor. most_common(3) te da el podio sin ordenar nada tú. Y una
clave que no existe devuelve cero en vez de reventar, que es
exactamente lo que quieres al contar.
Para agrupar, en vez de contar, está el otro:
por_ciudad = defaultdict(list) for v in movimientos: por_ciudad[v['ciudad']].append(v['monto']) for ciudad, montos in por_ciudad.items(): print(f'{ciudad:<10} {len(montos)} ventas, S/{sum(montos):>8.2f}')
Lima 3 ventas, S/ 3851.21 Arequipa 1 ventas, S/ 154.83 Cusco 1 ventas, S/ 524.90
La gracia está en el defaultdict(list): cuando le pides una clave
que no existe, se la inventa vacía en vez de fallar. Con un
diccionario normal, la primera venta de Lima revienta:
sin_default = {}
sin_default['Lima'].append(480.37)
KeyError: 'Lima'
Por eso el patrón de siempre es if ciudad not in d: d[ciudad] = []
antes de cada append. Con defaultdict esa línea
desaparece y el bucle se lee de un vistazo 🌸
Ordenar por dos cosas a la vez
Ya ordenaste una lista de números. Con una lista de diccionarios hay que
decirle por qué campo, y ahí entra key:
ordenadas = sorted(movimientos, key=lambda v: (v['ciudad'], -v['monto'])) for v in ordenadas: print(f"{v['ciudad']:<10} {v['categoria']:<12} {v['monto']:>8.2f}")
Arequipa Bebidas 154.83 Cusco Limpieza 524.90 Lima Abarrotes 2480.84 Lima Bebidas 890.00 Lima Abarrotes 480.37
Ciudad en orden alfabético, y dentro de cada ciudad los montos de mayor a menor 📊
El truco está en esa tupla que devuelve el
lambda. Python compara tuplas de izquierda a derecha: primero mira
la ciudad, y solo si empatan pasa al segundo elemento. Puedes poner tres o cuatro
criterios, y se comparan en ese orden.
Y el signo menos delante del monto es el truco para invertir solo ese
criterio. Con reverse=True le darías la vuelta a los dos, y
las ciudades te saldrían de la Z a la A. El menos solo funciona con números; para
invertir un texto hay que ordenar dos veces, primero por el criterio de dentro y
después por el de fuera.
Ejercicios
1. Primero, último y cuántos
Con una lista de cinco canales, imprime el primero, el último y cuántos hay, sin contar a mano.
canales = ['Web', 'Tienda', 'WhatsApp', 'Marketplace', 'Telefono'] print(canales[0], canales[-1], len(canales))
Web Telefono 5
2. Las tres del medio
De esa misma lista, saca solo los elementos 2, 3 y 4 con una rebanada.
print(canales[1:4])
['Tienda', 'WhatsApp', 'Marketplace']
Recuerda que el límite derecho no entra: 1:4 te da las posiciones
1, 2 y 3.
3. El top 3 de montos
De una lista de montos, saca los tres más altos ordenados de mayor a menor, sin modificar la lista original.
montos = [480.37, 154.83, 2480.84, 524.90, 95.5, 1200.0] top = sorted(montos, reverse=True)[:3] print(top) print(montos[0]) # la original intacta
[2480.84, 1200.0, 524.9] 480.37
4. Demuestra el aliasing
Crea una lista, hazle una copia falsa y una de verdad, y
comprueba con is cuál es cuál.
pedido = ['Abarrotes', 'Bebidas', 'Snacks'] falsa = pedido buena = pedido.copy() falsa.append('Limpieza') print(pedido) print(buena) print(falsa is pedido, buena is pedido)
['Abarrotes', 'Bebidas', 'Snacks', 'Limpieza'] ['Abarrotes', 'Bebidas', 'Snacks'] True False
is pregunta si son el mismo objeto; == pregunta si
tienen el mismo contenido. Dos listas distintas con lo mismo dentro dan
True con == y False con is.
5. Un diccionario que no revienta
Con un diccionario de una venta que no trae la clave
descuento, calcula el monto final asumiendo 0 si no está.
venta = {'cliente': 'C0325', 'monto': 524.90}
descuento = venta.get('descuento', 0)
print(f'S/{venta["monto"] * (1 - descuento):.2f}')
S/524.90
Fíjate en las comillas dobles dentro del f-string que abre con comillas simples. Si usas las mismas por fuera y por dentro, Python se pierde.
6. Contar por categoría
Con una lista de canales repetidos, cuenta cuántas veces aparece cada uno.
canales = ['Web', 'Tienda', 'Web', 'WhatsApp', 'Web', 'Tienda'] conteo = {} for c in canales: conteo[c] = conteo.get(c, 0) + 1 print(conteo)
{'Web': 3, 'Tienda': 2, 'WhatsApp': 1}
Es el mismo patrón de la suma por ciudad, pero sumando 1 en vez del monto.
Cuando lo veas escrito así vas a reconocer value_counts() de pandas
sin que nadie te lo explique.
7. El máximo con nombre
De una lista de diccionarios de ventas, encuentra la de mayor monto e imprime su ciudad.
ventas = [
{'ciudad': 'Lima', 'monto': 480.37},
{'ciudad': 'Cusco', 'monto': 2480.84},
{'ciudad': 'Piura', 'monto': 524.90},
]
mayor = max(ventas, key=lambda v: v['monto'])
print(mayor['ciudad'], mayor['monto'])
Cusco 2480.84
Ese lambda es una función chiquita sin nombre que dice "para
comparar, mira el monto". Lo vemos con calma en el capítulo 6, tranqui.
8. Comprensión con condición
De la lista de ventas anterior, arma una lista solo con las ciudades cuyo monto pase los S/500.
print([v['ciudad'] for v in ventas if v['monto'] > 500])
['Cusco', 'Piura']
9. Quitar duplicados conservando el orden
De una lista con ciudades repetidas, saca las únicas. Hazlo de dos formas y compara.
ciudades = ['Lima', 'Cusco', 'Lima', 'Piura', 'Cusco', 'Lima'] print(sorted(set(ciudades))) vistas = [] for c in ciudades: if c not in vistas: vistas.append(c) print(vistas)
['Cusco', 'Lima', 'Piura'] ['Lima', 'Cusco', 'Piura']
set() es rapidísimo y pierde el orden original; el bucle lo
conserva. Cuál usar depende de si el orden significa algo, y muchas veces
significa.
10. La tupla que no se deja
Crea una tupla con un rango de fechas e intenta cambiar el primer valor. Después haz lo mismo con una lista y compara.
rango_tupla = ('2026-01-01', '2026-12-31') rango_lista = ['2026-01-01', '2026-12-31'] rango_lista[0] = '2026-02-01' print(rango_lista) rango_tupla[0] = '2026-02-01'
TypeError: 'tuple' object does not support item assignment
La tupla te protege de un cambio accidental. Cuando algo no debe moverse en todo el programa, esa protección vale más que la flexibilidad.
11. Quién se fue y quién llegó
Con tres meses de códigos de cliente, di cuántos se mantuvieron, cuántos se perdieron y cuántos entraron nuevos.
meses = {
'enero': {'C0045', 'C0325', 'C0260', 'C0111'},
'febrero': {'C0325', 'C0045', 'C0777', 'C0888'},
'marzo': {'C0045', 'C0888', 'C0999'},
}
fieles = meses['enero'] & meses['febrero'] & meses['marzo']
alguna_vez = meses['enero'] | meses['febrero'] | meses['marzo']
print('clientes distintos en el trimestre:', len(alguna_vez))
print('compraron los tres meses :', sorted(fieles))
print('perdidos de enero a febrero :',
sorted(meses['enero'] - meses['febrero']))
print('nuevos en marzo :',
sorted(meses['marzo'] - meses['enero'] - meses['febrero']))
print('retencion enero -> febrero :',
round(len(meses['enero'] & meses['febrero']) / len(meses['enero']) * 100), '%')
clientes distintos en el trimestre: 7 compraron los tres meses : ['C0045'] perdidos de enero a febrero : ['C0111', 'C0260'] nuevos en marzo : ['C0999'] retencion enero -> febrero : 50 %
Un cliente de cuatro aguantó los tres meses, y la retención del primer mes al segundo es del 50% 📉
Con datos de verdad esto es el análisis de cohortes entero, y sale de tres conjuntos y cuatro operaciones. Ni una librería.
12. El podio, sin ordenar nada
Cuenta las ventas por categoría y saca las dos más frecuentes.
categorias = Counter(v['categoria'] for v in movimientos) print(categorias) print('el podio :', categorias.most_common(2)) print('cuantas hay :', len(categorias), 'categorias distintas') print('total ventas :', sum(categorias.values())) print('una que no esta:', categorias['Congelados'])
Counter({'Abarrotes': 2, 'Bebidas': 2, 'Limpieza': 1})
el podio : [('Abarrotes', 2), ('Bebidas', 2)]
cuantas hay : 3 categorias distintas
total ventas : 5
una que no esta: 0
Ese último cero es la razón por la que uso Counter y no un
diccionario normal 🛡️
Preguntar por una categoría que no vino este mes devuelve cero, que es la
respuesta correcta. Un diccionario normal te lanzaría un KeyError y
te tumbaría el reporte por una categoría que simplemente no vendió.
13. Agrupar montos por ciudad
Junta los montos de cada ciudad y saca el total, el promedio y el máximo de cada una.
agrupado = defaultdict(list) for v in movimientos: agrupado[v['ciudad']].append(v['monto']) for ciudad in sorted(agrupado): montos = agrupado[ciudad] print(f'{ciudad:<10} {len(montos)} ventas ' f'total S/{sum(montos):>9.2f} ' f'promedio S/{sum(montos) / len(montos):>8.2f} ' f'mayor S/{max(montos):>8.2f}')
Arequipa 1 ventas total S/ 154.83 promedio S/ 154.83 mayor S/ 154.83 Cusco 1 ventas total S/ 524.90 promedio S/ 524.90 mayor S/ 524.90 Lima 3 ventas total S/ 3851.21 promedio S/ 1283.74 mayor S/ 2480.84
Ese sorted(agrupado) del bucle ordena las claves alfabéticamente,
para que la tabla salga siempre igual. Sin él salen en el orden en que
aparecieron, que depende del archivo y cambia cada mes 🔀
Y esto es, literalmente, lo que hace groupby de pandas. Cuando
llegues a ese capítulo vas a saber qué está pasando por debajo.
14. Un ranking con dos criterios
Ordena las ventas por ciudad y, dentro de cada ciudad, de mayor a menor monto. Después dale la vuelta al criterio de fuera.
print('ciudad A-Z, monto de mayor a menor:') for v in sorted(movimientos, key=lambda v: (v['ciudad'], -v['monto'])): print(f" {v['ciudad']:<10} {v['monto']:>8.2f}") print('y ahora ciudad Z-A, monto de menor a mayor:') for v in sorted(movimientos, key=lambda v: (v['ciudad'], -v['monto']), reverse=True): print(f" {v['ciudad']:<10} {v['monto']:>8.2f}")
ciudad A-Z, monto de mayor a menor: Arequipa 154.83 Cusco 524.90 Lima 2480.84 Lima 890.00 Lima 480.37 y ahora ciudad Z-A, monto de menor a mayor: Lima 480.37 Lima 890.00 Lima 2480.84 Cusco 524.90 Arequipa 154.83
Mira lo que hizo el reverse=True: le dio la vuelta a
los dos criterios 🔄
Las ciudades pasaron de la Z a la A, pero los montos, que iban de mayor a
menor por el signo menos, ahora van de menor a mayor. El reverse no
distingue: invierte la comparación entera.
Por eso el signo menos es mejor herramienta cuando quieres criterios en direcciones distintas. Es más quisquilloso de escribir y te deja controlar cada uno por separado 🎛️
Quitar duplicados y quedarte con uno
Esta es la primera trampa de listas con la que se topa todo el mundo, y no avisa de ninguna manera: no revienta, no imprime nada raro, y la lista sale más corta como esperabas 🫥
La trampa
Limpias duplicados recorriendo la lista y quitando lo que sobra. Corre, no da error, y la lista sale más corta.
ciudades = ['lima', 'lima', 'cusco'] for c in ciudades: if c == 'lima': ciudades.remove(c) print(ciudades) # ['lima', 'cusco']
Qué está mal
Sobrevivió una Lima 👻 Al quitar la primera, todo lo de detrás se corre un sitio hacia la izquierda, pero el bucle ya va por la posición 1. Se salta la segunda Lima sin mirarla.
Y esto es lo peligroso: la lista sí se acortó, así que parece que funcionó. Con duplicados sueltos acierta, con duplicados pegados falla, y nadie revisa un limpiador de duplicados que devuelve menos filas de las que entraron.
Nunca se modifica una lista mientras se recorre. Se construye una nueva con una comprensión ([c for c in ciudades if c != 'lima']), que además se lee mejor y es más rápida.
Comprueba que lo tienes
Haces b = a con dos listas, cambias b y a también cambió. ¿Por qué?
- Porque las dos etiquetas apuntan a la misma lista
- Porque las listas se copian solas
- Porque hay que usar tuplas para que no cambien
- Porque b quedó dentro de a
Lo que te llevas
- 🔢 Se cuenta desde 0, y
[-1]es siempre el último. - ✂️ En una rebanada, el límite de la derecha no entra.
- ⚠️
copia = originalno copia nada: usa.copy(). - 🔀
sorted()devuelve una lista nueva;.sort()devuelveNone. - 🗂️ Una lista de diccionarios es como llega el mundo real, y agrupar con
.get(clave, 0)es el patrón que después hacegroupby.
Y si de todo el capítulo te llevas una sola frase, que sea esta:
Un diccionario no es una lista con nombres. Es la respuesta a "y esto de quién es".
Y si un diccionario te suena a "una fila con los nombres de las columnas", vas bien: es exactamente lo que devuelve una consulta, y de eso va el libro de SQL 🗃️
En el capítulo 5 le enseñamos a Python a decidir y a repetir: if,
for y while. Ahí es donde esto deja de ser una
calculadora y empieza a ser un programa.
Que tengas un hermoso día! 🌟
Preguntas frecuentes
¿Qué son las listas en Python?
Una secuencia ordenada de cosas que se puede modificar. Se escribe entre corchetes y el primer elemento es el cero.
¿Qué son los diccionarios en Python?
Pares de clave y valor. En vez de pedir el elemento tres pides el elemento "ciudad", que es como llegan casi todos los datos de una API.
¿Cuál es la diferencia entre lista y tupla?
La tupla no se puede modificar después de creada. Se usa para cosas que no deberían cambiar, como unas coordenadas.
¿Cómo copio una lista sin que se copie sola?
Con lista.copy() o con una rebanada completa. Si escribes b = a, las dos apuntan a la misma lista y modificar una modifica la otra, que es el error que más desconcierta al principio.
Practica este capítulo 📓
Todo el código de arriba en un cuaderno que corre de principio a fin, y los ejercicios con una celda vacía para que los hagas tú. Se abre en Google Colab de un clic y no hay que instalar nada. Donde veas %%revisa, escribe tu respuesta y el cuaderno te dice si te salió.
¿Prefieres trabajar en tu máquina? Bájate el cuaderno de práctica o el de soluciones. Todos están también en github.com/soymissyera/MissYeraEjercicios.