Listas y slicing

# ─────────────────────────────────────────────
# MODIFICAR LISTAS: ÍNDICES Y SLICES
# ─────────────────────────────────────────────

# Importación de un módulo propio (archivo iterar_cadenas.py)
# Por ahora no te preocupes por esto, lo veremos más adelante
from iterar_cadenas import posicion

lista = [1, 2, 3, 4, 5, 6, 7]

# Cambiar UN elemento por su índice (posición)
# El índice 3 corresponde al 4º elemento (se empieza a contar desde 0)
lista[3] = 11
print(lista)   # → [1, 2, 3, 11, 5, 6, 7]

# SLICE (rebanada): modificar VARIOS elementos a la vez
# lista[4:7] selecciona desde el índice 4 hasta el 6 (el 7 no se incluye)
# Los reemplazamos por tres nuevos valores
lista[4:7] = [91, 92, 93]
print(lista)   # → [1, 2, 3, 11, 91, 92, 93]

# Un slice puede reemplazarse por MENOS elementos de los que había
# Aquí sustituimos 2 elementos (índices 0 y 1) por solo 1
lista[0:2] = [1]
print(lista)   # → [1, 3, 11, 91, 92, 93]  ← la lista se encoge

# También puede reemplazarse por MÁS elementos de los que había
# Aquí sustituimos 2 elementos por 9 → la lista crece
lista[0:2] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(lista)   # → [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 91, 92, 93]

# ─────────────────────────────────────────────
# EXTEND: añadir elementos de otro iterable
# ─────────────────────────────────────────────

listilla = [1, 2, 3]

otralista = [7, 77, 777]
tupla     = (8, 88, 888)
cadena    = "abc"

# extend() añade cada elemento del iterable uno a uno al final de la lista
listilla.extend(otralista)   # Añade los elementos de una lista
print(listilla)              # → [1, 2, 3, 7, 77, 777]

listilla.extend(tupla)       # También funciona con tuplas
print(listilla)              # → [1, 2, 3, 7, 77, 777, 8, 88, 888]

listilla.extend(cadena)      # Con una cadena añade CADA LETRA por separado
print(listilla)              # → [1, 2, 3, 7, 77, 777, 8, 88, 888, 'a', 'b', 'c']


# ─────────────────────────────────────────────
# EXTEND vs APPEND: diferencia importante
# ─────────────────────────────────────────────

lista = [1, 2, 3]
lista.extend([4, 5])   # extend: desglosa la lista y añade cada elemento
print(lista)           # → [1, 2, 3, 4, 5]

lista = [1, 2, 3]
lista.append([4, 5])   # append: añade el objeto ENTERO como un único elemento
print(lista)           # → [1, 2, 3, [4, 5]]  ← ¡el último elemento es una lista!


# ─────────────────────────────────────────────
# LISTAS ANIDADAS (listas dentro de listas)
# ─────────────────────────────────────────────

# Cada alumno es una lista con su nombre y una tupla de notas
alumnos = [
    ["Ana", (1, 2, 3)],
    ["Pep", (4, 5, 6)],
    ["Iu",  (7, 8)]
]
# Para acceder: alumnos[0] → ["Ana", (1,2,3)]
#               alumnos[0][1] → (1, 2, 3)
#               alumnos[0][1][0] → 1


# ─────────────────────────────────────────────
# MÉTODOS PARA ELIMINAR ELEMENTOS
# ─────────────────────────────────────────────

frutas = ["pera", "manzana", "kiwi", "pera"]

# 'in' comprueba si un elemento existe en la lista
if "pera" in frutas:
    frutas.remove("pera")   # remove() elimina la PRIMERA ocurrencia del valor
print(frutas)               # → ['manzana', 'kiwi', 'pera']  ← queda una "pera"

# pop() elimina y DEVUELVE el último elemento (sin argumentos)
ultima_fruta = frutas.pop()
print(ultima_fruta)   # → 'pera'
print(frutas)         # → ['manzana', 'kiwi']

# pop(índice) elimina y devuelve el elemento en esa posición
primera_fruta = frutas.pop(0)
print(primera_fruta)  # → 'manzana'
print(frutas)         # → ['kiwi']


# ─────────────────────────────────────────────
# BUSCAR ELEMENTOS: index()
# ─────────────────────────────────────────────

lista = [2, 3, 4, 5, 4, 3, 2, 7, 8, 2]

# index(valor) devuelve la posición de la PRIMERA aparición del valor
posicion = lista.index(2)
print(posicion)   # → 0

# index(valor, inicio) busca a partir de una posición concreta
# Así podemos encontrar la 2ª, 3ª... aparición del mismo valor
posicion = lista.index(2, posicion + 1)   # Busca desde la posición 1 en adelante
print(posicion)   # → 6

posicion = lista.index(2, posicion + 1)   # Busca desde la posición 7 en adelante
print(posicion)   # → 9


# ─────────────────────────────────────────────
# ORDENAR LISTAS: sort()
# ─────────────────────────────────────────────

lista = [2, 3, 4, 5, 4, 3, 2, 7, 8, 2]

lista.sort()                  # Orden ascendente (de menor a mayor)
print(lista)                  # → [2, 2, 2, 3, 3, 4, 4, 5, 7, 8]

lista.sort(reverse=True)      # Orden descendente (de mayor a menor)
print(lista)                  # → [8, 7, 5, 4, 4, 3, 3, 2, 2, 2]

# sort(key=función): ordena según el valor que devuelve la función
# para cada elemento. Aquí los pares se quedan igual y los impares
# se "pesan" el doble, por lo que los pares van primero.
def mifuncion(num):
    if num % 2 == 0:
        return num        # Par: se usa su valor real
    else:
        return num * 2    # Impar: se usa el doble (ocupa más "peso" al ordenar)

lista.sort(key=mifuncion)
print(lista)   # → [2, 2, 2, 3, 4, 4, 3, 5, 7, 8]  (pares primero)

# Ordenar cadenas por su longitud usando len como función clave
lista = ["Ana", "Iu", "Eva", "Pep", "Rosa", "Juan", "Roc"]
lista.sort(key=len)    # len devuelve el número de caracteres de cada nombre
print(lista)           # → ['Iu', 'Ana', 'Eva', 'Pep', 'Roc', 'Rosa', 'Juan']


# ─────────────────────────────────────────────
# COPIA DE LISTAS: referencia vs copia real
# ─────────────────────────────────────────────

notas = [6, 7, 3, 5]

# ⚠️ ASIGNACIÓN DIRECTA: NO crea una copia, ambas variables apuntan
# al MISMO objeto en memoria. Cambiar una cambia la otra.
copia = notas

copia[1] = 9
print(copia)    # → [6, 9, 3, 5]
print(notas)    # → [6, 9, 3, 5]  ← ¡notas también cambió! Cuidado con esto.


notas = [6, 7, 3, 5]

# ✅ COPIA REAL con .copy(): crea un objeto nuevo e independiente
# Modificar 'copia' NO afecta a 'notas'
copia = notas.copy()

copia[1] = 9
print(copia)    # → [6, 9, 3, 5]
print(notas)    # → [6, 7, 3, 5]  ← notas no ha cambiado ✓

# ─────────────────────────────────────────────
# SLICES (REBANADAS): acceder a partes de una cadena o lista
# ─────────────────────────────────────────────
# Sintaxis general: coleccion[inicio:fin:paso]
#   · inicio: índice donde empieza la rebanada (se incluye)
#   · fin:    índice donde termina (NO se incluye)
#   · paso:   de cuánto en cuánto avanza (por defecto 1)

cadena = "Mi mamá me mima"
#índices:  0123456789...

# [inicio:fin] → caracteres desde el índice 2 hasta el 5 (el 6 no se incluye)
print(cadena[2:6])    # → ' mam'

# [:fin] → desde el principio hasta el índice 1 (el 2 no se incluye)
print(cadena[:2])     # → 'Mi'

# [inicio:] → desde el índice 5 hasta el final
print(cadena[5:])     # → 'má me mima'

# Índices NEGATIVOS: cuentan desde el final hacia atrás
# -1 es el último carácter, -2 el penúltimo, etc.
# [-3:] → los últimos 3 caracteres
print(cadena[-3:])    # → 'ima'


# ─────────────────────────────────────────────
# LOS MISMOS SLICES FUNCIONAN IGUAL CON LISTAS
# ─────────────────────────────────────────────

lista = ["Ana", "Iu", "Eva", "Pep", "Rosa", "Juan", "Roc"]
#índices:   0      1     2      3      4       5      6

print(lista[2:6])   # → ['Eva', 'Pep', 'Rosa', 'Juan']  (del índice 2 al 5)
print(lista[:2])    # → ['Ana', 'Iu']                   (los 2 primeros)
print(lista[5:])    # → ['Juan', 'Roc']                  (desde el índice 5 hasta el final)
print(lista[-3:])   # → ['Juan', 'Roc', ... ]            (los 3 últimos)


# ─────────────────────────────────────────────
# EL TERCER PARÁMETRO: el PASO
# ─────────────────────────────────────────────

# [::] → sin inicio, sin fin, paso por defecto (1) → copia entera
print(lista[::])    # → ['Ana', 'Iu', 'Eva', 'Pep', 'Rosa', 'Juan', 'Roc']

# [::2] → coge un elemento sí, uno no (paso 2)
#          índices 0, 2, 4, 6 → "Ana", "Eva", "Rosa", "Roc"
print(lista[::2])   # → ['Ana', 'Eva', 'Rosa', 'Roc']

# [::-1] → paso NEGATIVO: recorre la lista al revés
#           sin inicio ni fin → la lista completa invertida
print(lista[::-1])  # → ['Roc', 'Juan', 'Rosa', 'Pep', 'Eva', 'Iu', 'Ana']

# [::-2] → al revés de dos en dos
#           índices 6, 4, 2, 0 → "Roc", "Rosa", "Eva", "Ana"
print(lista[::-2])  # → ['Roc', 'Rosa', 'Eva', 'Ana']

# [6:2:-1] → hacia atrás desde el índice 6 hasta el 3 (el 2 no se incluye)
#             índices 6, 5, 4, 3 → "Roc", "Juan", "Rosa", "Pep"
print(lista[6:2:-1])  # → ['Roc', 'Juan', 'Rosa', 'Pep']

Publicado por

Juan Pablo Fuentes

Formador de programación y bases de datos