# =============================================================================
# RECORRER LISTAS EN PYTHON — PATRONES HABITUALES
# =============================================================================
# En este programa veremos tres patrones muy comunes cuando trabajamos con listas:
#
# 1. Buscar el elemento "mejor" de una lista (el más largo, el mayor, el menor...)
# 2. Filtrar una lista: quedarse solo con los elementos que cumplan una condición
# 3. Filtrar con condiciones sobre cadenas (primera letra, última letra...)
#
# Estos tres patrones aparecen constantemente en programas reales.
# =============================================================================
# =============================================================================
# PATRÓN 1: BUSCAR EL NOMBRE MÁS LARGO DE UNA LISTA
# =============================================================================
# Problema: dada una lista de nombres, ¿cuál es el más largo?
#
# Estrategia: "candidato provisional"
# Asumimos que el primero es el más largo.
# Recorremos el resto y si encontramos uno más largo, lo sustituimos.
# Al terminar, el candidato es el ganador real.
# =============================================================================
alumnos = ["Ana", "Rosa", "Pep", "Iu", "Felicia", "Juan"]
# Lista de nombres con la que vamos a trabajar.
# ALTERNATIVA: pedir los nombres al usuario con un bucle while.
nombre_mas_largo = alumnos[0]
# Tomamos el PRIMER elemento como candidato provisional al más largo.
# alumnos[0] → "Ana"
# No lo inicializamos a "" porque "" tiene longitud 0 y cualquier nombre
# sería más largo, lo que también funcionaría, pero esta forma es más clara.
# IMPORTANTE: hacerlo ANTES del bucle, no dentro.
for alumno in alumnos:
# Recorremos TODOS los alumnos, incluido "Ana" (el primero).
# Comparar "Ana" consigo mismo no causa ningún problema: len("Ana") > len("Ana")
# es False, así que simplemente no lo sustituimos. Todo correcto.
if len(alumno) > len(nombre_mas_largo):
# len() devuelve el número de caracteres de una cadena.
# len("Ana") → 3
# len("Felicia") → 7
# Si el alumno actual tiene MÁS letras que el candidato actual...
nombre_mas_largo = alumno
# ...actualizamos el candidato. Ahora este es el más largo provisional.
# Vuelta a vuelta:
# "Ana" → candidato="Ana" (inicial)
# "Rosa" → 4 > 3 → candidato="Rosa"
# "Pep" → 3 > 4 → NO cambia
# "Iu" → 2 > 4 → NO cambia
# "Felicia" → 7 > 4 → candidato="Felicia"
# "Juan" → 4 > 7 → NO cambia
print(nombre_mas_largo)
# → "Felicia"
#
# RETO: modifica el código para encontrar también el nombre MÁS CORTO.
# Pista: solo tienes que cambiar > por < y el nombre de la variable.
# =============================================================================
# PATRÓN 2: FILTRAR NÚMEROS DE UNA LISTA
# =============================================================================
notas = [3, 6, 7, 8, 2, 4, 9, 10]
# Lista de notas con la que trabajaremos.
# Queremos saber cuántos alumnos han aprobado y cuántos han suspendido.
# -----------------------------------------------------------------------------
# FUNCIÓN lista_mayores_que(lista, umbral)
# -----------------------------------------------------------------------------
# Recibe una lista de números y un umbral.
# Devuelve una nueva lista con solo los números ESTRICTAMENTE mayores que el umbral.
# La lista original no se modifica.
#
# Ejemplos:
# lista_mayores_que([1, 5, 3, 8, 2, 9], 4) → [5, 8, 9]
# lista_mayores_que([7, 7, 7], 7) → [] (7 no es mayor QUE 7)
def lista_mayores_que(lista, umbral):
# Dos parámetros:
# "lista" → la lista de números que queremos filtrar
# "umbral" → el valor límite. Solo pasarán los números que lo superen.
resultado = []
# Lista vacía donde iremos guardando los números que cumplan la condición.
# Debe crearse DENTRO de la función para que empiece vacía en cada llamada.
# Si estuviera fuera, las llamadas anteriores dejarían números sobrantes.
for numero in lista:
# Recorremos cada número de la lista que nos han pasado.
if numero > umbral:
# Comprobamos si supera el umbral.
# OJO: es > (estrictamente mayor), no >= (mayor o igual).
# Por eso lista_mayores_que([7,7,7], 7) devuelve [] y no [7,7,7].
# Si quisiéramos incluir el umbral cambiaríamos > por >=.
resultado.append(numero)
# .append() añade el número AL FINAL de la lista resultado.
# Solo llegamos aquí si el número supera el umbral.
return resultado
# Devolvemos la lista con los números seleccionados.
# Si ningún número superó el umbral, devolvemos [] (lista vacía).
# --- Casos de prueba ---
mayores = lista_mayores_que([1, 5, 3, 8, 2, 9], 4)
print(mayores)
# → [5, 8, 9]
# Guardamos el resultado en "mayores" para poder usarlo después si queremos.
print(lista_mayores_que([2, 10, 7, 40, 8, 3], 7)) # → [10, 40, 8]
print(lista_mayores_que([10, 20, 30], 15)) # → [20, 30]
print(lista_mayores_que([1, 2, 3], 10)) # → []
print(lista_mayores_que([7, 7, 7], 7)) # → []
# --- Uso práctico con las notas ---
# Aprobados: notas mayores que 4 (es decir, 5 o más)
# Suspensos: notas menores o iguales a 4
aprobados = lista_mayores_que(notas, 4)
# → [6, 7, 8, 9, 10]
# len(aprobados) nos diría cuántos hay: len([6,7,8,9,10]) = 5
# =============================================================================
# PATRÓN 3: FILTRAR NOMBRES SEGÚN SUS LETRAS
# =============================================================================
# Ahora filtramos una lista de cadenas comprobando la primera y última letra.
# Veremos dos herramientas nuevas:
# nombre[0] → primera letra ("Ana"[0] → "A")
# nombre[-1] → última letra ("Ana"[-1] → "a")
# .lower() → convierte a minúscula para ignorar mayúsculas/minúsculas
# -----------------------------------------------------------------------------
# FUNCIÓN nombres_con_a(nombres)
# -----------------------------------------------------------------------------
# Recibe una lista de nombres.
# Devuelve una nueva lista con los nombres que empiecen O acaben por 'a' (o 'A').
#
# Ejemplos:
# nombres_con_a(["Ana", "Pedro", "María", "Jordi", "Almudena"])
# → ["Ana", "María", "Almudena"]
def nombres_con_a(nombres):
resultado = []
# Lista vacía donde iremos guardando los nombres que cumplan la condición.
for nombre in nombres:
# Recorremos cada nombre de la lista.
letra_inicial = nombre[0].lower()
# nombre[0] → primera letra del nombre. "Ana"[0] → "A"
# .lower() → la convertimos a minúscula. "A".lower() → "a"
# Así "Ana", "ANA" y "ana" funcionan igual: siempre comparamos con "a".
# Sin .lower(), "Ana" empezaría por "A" y no pasaría el if letra=="a".
letra_final = nombre[-1].lower()
# nombre[-1] → última letra del nombre.
# Los índices negativos en Python cuentan desde el final:
# nombre[-1] → última letra
# nombre[-2] → penúltima letra
# "María"[-1] → "a" "Pedro"[-1] → "o"
# .lower() por el mismo motivo que antes.
if letra_inicial == "a" or letra_final == "a":
# "or" → basta con que UNA de las dos condiciones sea True.
# Si el nombre empieza por 'a' → entra.
# Si el nombre acaba por 'a' → entra.
# Si cumple las DOS → también entra, pero solo se añade UNA vez.
# Si no cumple ninguna → no entra.
#
# Repaso con cada nombre de la prueba:
# "Ana" → inicial="a" ✓ → entra
# "Pedro" → inicial="p", final="o" → NO entra
# "María" → inicial="m", final="a" ✓ → entra
# "Jordi" → inicial="j", final="i" → NO entra
# "Almudena" → inicial="a" ✓, final="a" ✓ → entra (una sola vez)
resultado.append(nombre)
# Añadimos el nombre original (con sus mayúsculas/minúsculas originales)
# no la versión .lower(). Queremos devolver "Ana", no "ana".
return resultado
# Devolvemos la lista con los nombres seleccionados.
# --- Casos de prueba ---
con_a = nombres_con_a(["Ana", "Pedro", "María", "Jordi", "Almudena"])
print(con_a)
# → ["Ana", "María", "Almudena"]