Python ofrece varias estructuras de datos incorporadas que facilitan la organización y manipulación de la información. Comúnmente se les conoce como “colecciones”.

Además cada estructura de datos posee métodos que permiten manipularla. Los métodos se acceden mediante un punto, por ejemplo:

# usando el método "append" de la lista "mi_lista" para agregar un elemento
mi_lista.append(10)

Normalmente los métodos modifican la propia estructura, por lo que no se debe reasignar el resultado a la misma variable. Sin embargo algunos métodos generan información nueva a partir de la estructura, y en esos casos podría ser relevante almacenar esa información.

Listas

Una lista es una colección ordenada y mutable. Puedes crearlas utilizando corchetes [].

mi_lista = [1, 2, 3, 4, 5]

Las listas pueden contener elementos de distinto tipo, e incluso otras listas o cualquier colección.

mi_lista_mixta = [1, "abc", False, [0.2, 4.5, 4]]

Para acceder a un elemento concreto de una lista se utiliza su índice :

mi_lista = ["a", "b", "c", "d", "e"]
mi_lista[2]  # "c"

Listas vs Arreglos

Python no tiene arreglos como en C y otros lenguajes; en su lugar, usa listas dinámicas que pueden contener elementos de distintos tipos. A diferencia de los arreglos en otros lenguajes, las listas en Python son más flexibles pero menos eficientes en memoria.

Métodos comunes en listas

  • .append(valor): Añade un elemento al final de la lista.
  • .insert(index, valor): Inserta un elemento en un índice específico.
  • .remove(valor): Elimina un elemento específico por su valor.
  • .pop(index): Similar a remove, pero además retorna el elemento eliminado. De no indicarse index, elimina y retorna el último elemento de la lista.
  • .extend(lista), “añade” una lista a otra.

Slicing

El “slicing” permite acceder a un subconjunto de elementos de una colección ordenada. Por tanto aplica a listas, pero también a tuplas y a strings.

La sintaxis básica es

coleccion[inicio:fin:paso]

en donde inicio y fin indican los límites de la subcolección que quieres extraer, y paso el intervalo entre los elementos seleccionados. Los slices son son cero-basados, y excluyen el último índice:

mi_lista = [1, 2, 3, 4, 5]
mi_sublista = mi_lista[1:4]  # [2, 3, 4]

Si omites cualquiera de los valores inicio, final o paso, Python usará los valores por defecto. Incluso, puedes utilizar valores negativos para recorrer la colección en sentido inverso.

Ejemplos:

lista = [0, 1, 2, 3, 4, 5]
lista[1:4]   # [1, 2, 3]
lista[:4]    # [0, 1, 2, 3]
lista[2:]    # [2, 3, 4, 5]
lista[::2]   # [0, 2, 4]
lista[::-1]  # [5, 4, 3, 2, 1, 0] - invierte la lista

Tuplas

Una tupla es una colección ordenada que en la mayoría de los casos se comporta de la misma manera que una lista, pero se diferencia en que es inmutable, es decir, no permite modificaciones. Se define con paréntesis ().

mi_tupla = (1, 2, 3, 4, 5)
mi_tupla[0] = 10  # esto no es posible con una tuple

Conjuntos (Sets)

Un conjunto es una colección no ordenada y sin elementos duplicados. Se define con llaves {}.

mi_conjunto = {1, 2, 3, 4, 5}

Ventajas de los conjuntos

Los conjuntos son especialmente útiles cuando deseamos agregar elementos y/o comprobar si los elementos están dentro del conjunto. A pesar de que esto se puede lograr igual con listas, es mucho más rápido usando conjuntos.

Métodos comunes en conjuntos

  • .add(): Añadir elemento.
  • .remove(): Eliminar elemento.
  • .union(): Unir dos conjuntos.

Diccionarios

Un diccionario es una colección no ordenada de pares clave-valor. Son muy utilizados para almacenar datos de forma organizada. Se define con llaves {}, igual que los conjuntos, pero se diferencia en que lleva la asociación de claves y valores.

mi_diccionario = {"nombre": "Juan", "edad": 30, "ciudad": "Madrid"}

Puedes acceder y modificar los elementos de un diccionario utilizando la notación de corchetes [], con el nombre de la clave.

nombre = mi_diccionario["nombre"]  # acceso
mi_diccionario["edad"] = 31  # modificación

También puedes utilizar el método get(), que tiene como ventaja permitirte añadir un valor por defecto en caso de una clave no exista.

mi_diccionario.get("nombre")  # "Juan"
mi_diccionario.get("mascotas", 0)  # 0, porque "mascotas" no está

Para eliminar un valor de un diccionario utiliza del, de esta manera:

del mi_diccionario["nombre"]

Métodos comunes en diccionarios

  • .keys(): Obtiene las claves.
  • .values(): Obtiene los valores.
  • .items(): Obtiene tuplas con la clave y el valor de cada una de las entradas del diccionario.

¿Cómo iterar sobre colecciones?

El ciclo de tipo for está diseñado para iterar sobre colecciones, entonces basta con hacer lo siguiente:

mascotas = ["Boby", "Michi", "Zoe", "Blacky"]
for mascota in mascotas:
    print(mascota)

Es importante tener en cuenta que mascota no es un índice, es el valor del propio elemento.

Si quieres tener un índice asociado a cada elemento, utiliza la función enumerate():

mascotas = ["Boby", "Michi", "Zoe", "Blacky"]
for i, mascota in enumerate(mascotas):
    print(i, mascota)

Al usar enumerate realmente obtienes una tupla, la cual puedes “separar” en dos variables mediante una característica llamada “unpacking”.

En el caso de los diccionarios, al iterar obtienes sólo las claves. Si quieres obtener los valores debes utilizar el método .values() o si quieres ambas cosas puedes utilizar .items().

Unpacking

El uso de unpacking te permite separar tuplas o listas en cualquier parte del código. Por ejemplo:

persona = ("Ana", 25)
nombre, edad = persona

Hay usos más avanzados del unpacking, que te permiten expandir todos los valores mediante el uso de * (para listas y tuplas) y ** para diccionarios. Esto puede ser útil para algunas ocasiones, por ejemplo pasar argumentos a una función en base a un diccionario.

Declaración por comprensión

La comprensión de listas permite definir colecciones “sobre la marcha” usando un ciclo for dentro de la propia definición. Por ejemplo, para crear una lista con los cuadrados de una lista de números:

mis_numeros = [1, 5, 6, 7, 13, 16]
mis_cuadrados = [numero**2 for numero in mis_numeros]

El código anterior es equivalente a lo siguiente, donde se declara una lista y se va añadiendo un elemento en cada iteración:

mis_cuadrados = []
for numero in mis_numeros:
    mis_cuadrados.append(numero**2)

También puedes aplicar condiciones, como seleccionar solo los números impares:

mis_cuadrados = [numero**2 for numero in mis_numeros if numero % 2 == 1]

La comprensión también funciona para diccionarios:

letras = ["A", "C", "G", "T"]
conteo = {letra: 0 for letra in letras}