Parte I — Las Aldeas del Bosque 🌲

Listas, Acceso, Slicing, Recorridos y Comprensiones

🌱 Bienvenida al Bosque

En esta primera etapa, el Explorador recorre las Aldeas de las Listas.

Estas notas de clase enfatizan cómo piensa Python frente a Java: secuencias dinámicas, acceso flexible y expresividad mediante comprensiones.

🧺 Crear listas

# Crear una lista de frutas
frutas = ["manzana", "pera", "uva"]
print(frutas)

Nota: En Python, las listas son dinámicas (pueden cambiar de tamaño). En Java, un arreglo tiene tamaño fijo.

🎯 Acceso por índice y por cortes (slicing)

frutas = ["manzana", "pera", "uva", "banano", "mango"]
primero = frutas[0]        # índice 0
ultimos_dos = frutas[-2:]  # últimos dos elementos
salteados = frutas[::2]    # toma cada 2 elementos
print(primero, ultimos_dos, salteados)

Nota: lista[inicio:fin:paso] no copia elemento a elemento; crea una vista por rango. En Java, se suele requerir bucles o utilidades adicionales.

🔁 Recorrer listas (for “pythónico”)

frutas = ["manzana", "pera", "uva"]
for fruta in frutas:
    print(f"• {fruta}")

Nota: El for en Python itera por elementos de la secuencia. En Java, típicamente se usaría for (String f : frutas) o índices; la semántica es similar, pero Python elimina la verbosidad.

🧳 Enumerar con índices (enumerate)

frutas = ["manzana", "pera", "uva"]
for i, fruta in enumerate(frutas, start=1):
    print(i, fruta)

Nota: enumerate devuelve parejas (índice, valor). En Java, habría que gestionar manualmente el índice.

➕➖ Agregar y quitar elementos

numeros = [10, 20, 30]
numeros.append(40)      # agrega al final
numeros.insert(1, 15)   # inserta en la posición 1
print(numeros)

el_ultimo = numeros.pop()   # quita y retorna el último
del numeros[0]              # elimina por posición
numeros.remove(20)          # elimina por valor (primera aparición)
print(numeros)

Nota: Métodos de mutación comunes: append, extend, insert, pop, remove, clear.

🔎 Búsqueda de elementos

letras = ["a", "b", "c", "b"]
existe_b = "b" in letras
pos_b = letras.index("b")   # primera aparición
print(existe_b, pos_b)

Nota: El operador in revisa existencia; index reporta la primera posición o lanza ValueError si no existe.

📊 Ordenamiento

nums = [5, 2, 9, 1]
nums.sort()              # in-place (modifica la lista)
print(nums)
nums.sort(reverse=True)  # descendente
print(nums)

nuevos = sorted(nums)    # retorna una nueva lista ordenada
print(nuevos)

Nota: list.sort() muta; sorted() crea una copia ordenada.

🧠 Claves de orden: key=

palabras = ["python", "Java", "ciencia", "Datos"]
palabras.sort(key=str.lower)          # ignora mayúsculas/minúsculas
ordenadas = sorted(palabras, key=len) # por longitud
print(palabras, ordenadas)

Nota: key recibe una función que transforma cada elemento a una clave comparable.

✨ Comprensiones de listas (List Comprehensions)

numeros = [1, 2, 3, 4, 5]
cuadrados = [n**2 for n in numeros]
pares = [n for n in numeros if n % 2 == 0]
print(cuadrados, pares)

Nota: Expresiones compactas y declarativas. Equivalen a map/filtrar pero con sintaxis clara. En Java se haría con Streams (map, filter), más verboso.

🧩 Desempaquetado (Unpacking) básico

punto = [10, 20]
x, y = punto
print(x, y)

a, b, *resto = [1, 2, 3, 4, 5]   # operador estrella
print(a, b, resto)

Nota: El operador * captura el “resto” de elementos.

🧭 Comparación con Java — idea clave

  • Python favorece expresiones declarativas y concisas para transformar colecciones.
  • Evita “ceremonia” (tipos explícitos, bucles verbosos) cuando no aporta al objetivo.

💭 Checkpoint (Reflexión)

  1. ¿Qué ocurre si intento acceder a frutas[100] en una lista de 3 elementos?
  1. Devuelve None • b) Lanza IndexError • c) Expande la lista
  1. ¿Qué diferencia hay entre sort() y sorted()?
  1. Ninguna
  2. sort muta y sorted retorna copia
  3. Al revés

💭 Checkpoint (Reflexión)

  1. ¿Qué hace *[1,2,3] en un contexto de llamada?
  1. Repite la lista • b) Desempaqueta sus elementos como argumentos • c) La convierte en tupla