0%
Estructuras de datos en Python: listas, tuplas, diccionarios y conjuntos

Estructuras de datos

Organiza y manipula tus datos con eficacia

10-15 min

Estructuras de datos en Python: listas, tuplas, diccionarios y conjuntos

Las estructuras de datos son formatos especializados para organizar, almacenar y manipular información. Python dispone de varias estructuras de datos integradas que facilitan la gestión de colecciones de elementos. En este tutorial exploraremos las cuatro estructuras de datos principales de Python: listas, tuplas, diccionarios y conjuntos.

Comprender estas estructuras y saber cuándo usar cada una es esencial para escribir código Python eficaz y elegante.

Listas

Las listas son una de las estructuras de datos más versátiles y utilizadas en Python. Una lista es una colección ordenada y modificable de elementos.

Creación de listas

# Lista vacía
ma_liste = []

# Lista con elementos
nombres = [1, 2, 3, 4, 5]
fruits = ["pomme", "banane", "orange"]
mixte = [1, "hello", 3.14, True]  # Puede contener distintos tipos

# Creación con la función list()
caracteres = list("Python")  # ['P', 'y', 't', 'h', 'o', 'n']

Acceso a los elementos de una lista

Los elementos de una lista se indexan a partir de 0.

fruits = ["pomme", "banane", "orange", "fraise", "kiwi"]

# Acceso por índice positivo (desde el inicio)
premier_fruit = fruits[0]  # "pomme"
troisieme_fruit = fruits[2]  # "orange"

# Acceso por índice negativo (desde el final)
dernier_fruit = fruits[-1]  # "kiwi"
avant_dernier = fruits[-2]  # "fraise"

# Rebanado (slicing)
deux_premiers = fruits[0:2]  # ["pomme", "banane"]
du_deuxieme_au_quatrieme = fruits[1:4]  # ["banane", "orange", "fraise"]
tous_sauf_premier = fruits[1:]  # ["banane", "orange", "fraise", "kiwi"]
trois_premiers = fruits[:3]  # ["pomme", "banane", "orange"]

Modificación de las listas

fruits = ["pomme", "banane", "orange"]

# Modificación de un elemento
fruits[1] = "poire"  # ["pomme", "poire", "orange"]

# Añadir elementos
fruits.append("fraise")  # Añade al final: ["pomme", "poire", "orange", "fraise"]
fruits.insert(1, "kiwi")  # Inserta en el índice 1: ["pomme", "kiwi", "poire", "orange", "fraise"]
fruits.extend(["cerise", "raisin"])  # Añade varios elementos: ["pomme", "kiwi", "poire", "orange", "fraise", "cerise", "raisin"]

# Eliminar elementos
fruits.remove("poire")  # Elimina la primera ocurrencia de "poire"
fruit_supprime = fruits.pop(2)  # Elimina y devuelve el elemento en el índice 2
del fruits[0]  # Elimina el elemento en el índice 0
fruits.clear()  # Vacía la lista por completo

Operaciones habituales sobre las listas

nombres = [3, 1, 4, 1, 5, 9, 2, 6]

# Longitud
longueur = len(nombres)  # 8

# Mínimo y máximo
minimum = min(nombres)  # 1
maximum = max(nombres)  # 9

# Suma
total = sum(nombres)  # 31

# Ordenación
nombres.sort()  # Ordena la lista in situ: [1, 1, 2, 3, 4, 5, 6, 9]
nombres_decroissants = sorted(nombres, reverse=True)  # Devuelve una nueva lista ordenada: [9, 6, 5, 4, 3, 2, 1, 1]

# Inversión
nombres.reverse()  # Invierte la lista in situ

# Conteo
occurrences_de_1 = nombres.count(1)  # 2

# Búsqueda de índice
premier_index_de_1 = nombres.index(1)  # Índice de la primera ocurrencia de 1

Comprensión de lista

La comprensión de lista es una sintaxis concisa para crear listas a partir de secuencias existentes.

# Sin comprensión de lista
carres = []
for x in range(10):
    carres.append(x**2)

# Con comprensión de lista
carres = [x**2 for x in range(10)]  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# Con condición
nombres_pairs = [x for x in range(20) if x % 2 == 0]  # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# Comprensión de lista más compleja
matrice = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
aplati = [nombre for ligne in matrice for nombre in ligne]  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

Casos de uso habituales de las listas

Las listas son ideales cuando necesitas:

  • Almacenar una colección de elementos en un orden específico
  • Modificar con frecuencia la colección (añadir/eliminar elementos)
  • Acceder a los elementos por su posición
  • Almacenar duplicados

Ejemplos de aplicaciones:

  • Lista de tareas
  • Historial de acciones
  • Colas de procesamiento
  • Series temporales de datos

Tuplas

Las tuplas son similares a las listas, pero son inmutables (no se pueden modificar tras su creación). Esta característica las hace más eficientes en memoria y rendimiento.

Creación de tuplas

# Tupla vacía
mon_tuple = ()

# Tupla con un solo elemento (requiere una coma)
singleton = (42,)

# Tupla con varios elementos
coordonnees = (10, 20)
personne = ("Alice", 30, "Ingénieure")

# Creación sin paréntesis (packing)
autre_tuple = 1, 2, 3

# Creación con la función tuple()
caracteres = tuple("Python")  # ('P', 'y', 't', 'h', 'o', 'n')

Acceso a los elementos de una tupla

El acceso a los elementos de una tupla funciona igual que en las listas:

coordonnees = (10, 20, 30, 40, 50)

x = coordonnees[0]  # 10
y = coordonnees[1]  # 20
dernier = coordonnees[-1]  # 50
sous_tuple = coordonnees[1:4]  # (20, 30, 40)

Desempaquetado de tupla (unpacking)

Una característica especialmente útil de las tuplas es el desempaquetado:

# Desempaquetado básico
point = (10, 20)
x, y = point  # x = 10, y = 20

# Desempaquetado con * para capturar varios elementos
premier, *milieu, dernier = (1, 2, 3, 4, 5)
# premier = 1, milieu = [2, 3, 4], dernier = 5

# Intercambio de variables
a, b = 1, 2
a, b = b, a  # a = 2, b = 1

Operaciones sobre las tuplas

coordonnees = (10, 20, 30)
plus_dimensions = coordonnees + (40, 50)  # Concatenación: (10, 20, 30, 40, 50)
repete = coordonnees * 2  # Repetición: (10, 20, 30, 10, 20, 30)

Métodos de tupla

Como las tuplas son inmutables, tienen menos métodos que las listas:

nombres = (3, 1, 4, 1, 5, 9, 2)

longueur = len(nombres)  # 7
occurrences_de_1 = nombres.count(1)  # 2
premier_index_de_1 = nombres.index(1)  # 1

Casos de uso habituales de las tuplas

Las tuplas son preferibles cuando:

  • Tienes una colección de elementos que no cambiará
  • Quieres impedir la modificación accidental de los datos
  • Necesitas una clave hashable para los diccionarios (las listas no pueden ser claves)
  • Devuelves varios valores desde una función

Ejemplos de aplicaciones:

  • Coordenadas (x, y, z)
  • Registros de base de datos
  • Claves compuestas
  • Valores RGB de colores
  • Parámetros de configuración fijos

Diccionarios

Los diccionarios son colecciones no ordenadas de pares clave-valor. Permiten un acceso, inserción y eliminación rápidos de elementos por clave.

Creación de diccionarios

# Diccionario vacío
mon_dict = {}

# Diccionario con pares clave-valor
etudiant = {
    "nom": "Martin",
    "age": 22,
    "cours": ["Mathématiques", "Informatique", "Physique"]
}

# Creación con la función dict()
coordonnees = dict(x=10, y=20, z=30)

# Creación a partir de tuplas clave-valor
items = [("pomme", 3), ("banane", 5), ("orange", 2)]
inventaire = dict(items)

# Diccionario por comprensión
carre_des_nombres = {x: x**2 for x in range(6)}  # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

Acceso y modificación de valores

etudiant = {
    "nom": "Martin",
    "age": 22,
    "cours": ["Mathématiques", "Informatique", "Physique"]
}

# Acceso a los valores
nom = etudiant["nom"]  # "Martin"

# Modificación de valores
etudiant["age"] = 23
etudiant["cours"].append("Chimie")

# Acceso seguro con get()
telephone = etudiant.get("telephone")  # None porque la clave no existe
telephone = etudiant.get("telephone", "Non spécifié")  # Valor por defecto "Non spécifié"

# Añadir un nuevo par clave-valor
etudiant["email"] = "martin@example.com"

# Eliminación
cours = etudiant.pop("cours")  # Elimina y devuelve el valor
del etudiant["age"]  # Elimina el par clave-valor
etudiant.clear()  # Vacía el diccionario

Métodos de diccionario

produits = {
    "pomme": 0.80,
    "banane": 0.50,
    "orange": 0.70
}

# Recuperación de claves, valores e items
cles = produits.keys()  # dict_keys(['pomme', 'banane', 'orange'])
valeurs = produits.values()  # dict_values([0.8, 0.5, 0.7])
items = produits.items()  # dict_items([('pomme', 0.8), ('banane', 0.5), ('orange', 0.7)])

# Actualización del diccionario
nouveaux_produits = {"kiwi": 1.20, "banane": 0.55}
produits.update(nouveaux_produits)  # Añade "kiwi" y modifica el precio de "banane"

# Comprobación de existencia de una clave
if "pomme" in produits:
    print("Le prix des pommes est", produits["pomme"])

Iteración sobre los diccionarios

produits = {
    "pomme": 0.80,
    "banane": 0.50,
    "orange": 0.70
}

# Iteración sobre las claves (comportamiento por defecto)
for produit in produits:
    print(produit)

# Iteración sobre los valores
for prix in produits.values():
    print(prix)

# Iteración sobre los pares clave-valor
for produit, prix in produits.items():
    print(f"{produit}: {prix}€")

Diccionarios anidados

# Diccionario de diccionarios
etudiants = {
    "101": {
        "nom": "Alice",
        "age": 22,
        "cours": ["Math", "Informatique"]
    },
    "102": {
        "nom": "Bob",
        "age": 21,
        "cours": ["Physique", "Biologie"]
    }
}

# Acceso a elementos anidados
nom_etudiant_102 = etudiants["102"]["nom"]  # "Bob"
cours_alice = etudiants["101"]["cours"][1]  # "Informatique"

Casos de uso habituales de los diccionarios

Los diccionarios son perfectos para:

  • Colecciones en las que buscas elementos por una clave única
  • Almacenamiento de datos asociativos (pares clave-valor)
  • Tablas hash rápidas para la búsqueda
  • Representación de objetos con atributos

Ejemplos de aplicaciones:

  • Caché de datos
  • Conteo de frecuencias
  • Bases de datos en memoria
  • Parámetros de configuración
  • Almacenamiento de propiedades de objetos JSON

Conjuntos

Los conjuntos (sets) son colecciones no ordenadas de elementos únicos. Están optimizados para comprobar pertenencia y eliminar duplicados.

Creación de conjuntos

# Conjunto vacío (no se puede usar {}, porque eso crea un diccionario vacío)
mon_ensemble = set()

# Conjunto con elementos
couleurs = {"rouge", "vert", "bleu"}

# Creación a partir de una lista (elimina duplicados)
nombres = set([1, 2, 2, 3, 4, 4, 5])  # {1, 2, 3, 4, 5}

# Conjunto por comprensión
nombres_pairs = {x for x in range(10) if x % 2 == 0}  # {0, 2, 4, 6, 8}

Operaciones sobre los conjuntos

fruits1 = {"pomme", "banane", "orange"}
fruits2 = {"orange", "kiwi", "ananas"}

# Añadir y eliminar elementos
fruits1.add("fraise")
fruits1.remove("banane")  # Lanza un error si el elemento no existe
fruits1.discard("cerise")  # No lanza error si el elemento no existe
element = fruits1.pop()  # Elimina y devuelve un elemento arbitrario
fruits1.clear()  # Vacía el conjunto

# Comprobación de pertenencia
"orange" in fruits2  # True
"banane" in fruits2  # False

Operaciones de conjuntos

Los conjuntos permiten realizar operaciones matemáticas de teoría de conjuntos:

A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}

# Unión (elementos que están en A O en B)
union = A | B  # {1, 2, 3, 4, 5, 6, 7, 8}
# o
union = A.union(B)

# Intersección (elementos que están en A Y en B)
intersection = A & B  # {4, 5}
# o
intersection = A.intersection(B)

# Diferencia (elementos que están en A pero NO en B)
difference = A - B  # {1, 2, 3}
# o
difference = A.difference(B)

# Diferencia simétrica (elementos que están en A O B pero NO en ambos)
diff_sym = A ^ B  # {1, 2, 3, 6, 7, 8}
# o
diff_sym = A.symmetric_difference(B)

# Comprobar si un conjunto es subconjunto de otro
est_sous_ensemble = {1, 2}.issubset(A)  # True

# Comprobar si un conjunto es superconjunto de otro
est_sur_ensemble = A.issuperset({1, 2})  # True

Conjuntos congelados (frozenset)

Un frozenset es un conjunto inmutable, lo que lo hace hashable. Puede usarse como clave de diccionario.

# Creación de un frozenset
couleurs_primaires = frozenset(["rouge", "bleu", "jaune"])

# Uso como clave de diccionario
groupes_couleurs = {
    frozenset(["rouge", "bleu", "jaune"]): "primaires",
    frozenset(["violet", "orange", "vert"]): "secondaires"
}

Casos de uso habituales de los conjuntos

Los conjuntos son especialmente útiles para:

  • Eliminar duplicados de una colección
  • Comprobar rápidamente la pertenencia de elementos
  • Realizar operaciones matemáticas sobre conjuntos
  • Encontrar elementos únicos o comunes entre colecciones

Ejemplos de aplicaciones:

  • Filtrado de duplicados
  • Análisis de datos únicos
  • Operaciones sobre conjuntos de tags
  • Gestión de permisos de usuarios
  • Representación de grafos (teoría de conjuntos)

Elegir la estructura de datos adecuada

Cada estructura de datos tiene sus fortalezas y debilidades. Aquí un cuadro comparativo para ayudarte a elegir la más adecuada a tu necesidad:

EstructuraOrdenadaModificableElementos indexadosElemento clave-valorElementos únicosCaso de uso típico
Lista✅✅✅❌❌Colección ordenada modificable
Tupla✅❌✅❌❌Colección ordenada inmutable
Diccionario❌¹✅❌✅✅ (claves)Mapeo clave-valor
Conjunto❌✅❌❌✅Eliminación de duplicados, operaciones de conjuntos

¹ Desde Python 3.7, los diccionarios conservan el orden de inserción, pero no se consideran intrínsecamente ordenados en su diseño.

Consejos para elegir la estructura adecuada

  • Usa una lista cuando el orden y la modificación son importantes
  • Usa una tupla para datos de solo lectura o claves compuestas
  • Usa un diccionario para búsquedas rápidas por clave
  • Usa un conjunto cuando la unicidad y las operaciones de conjuntos son necesarias

Ejemplo práctico: análisis de datos

Aquí un ejemplo que usa todas las estructuras de datos para analizar ventas:

# Datos de ventas (producto, cantidad, precio, categoría)
ventes = [
    ("pomme", 5, 0.80, "fruits"),
    ("banane", 3, 0.50, "fruits"),
    ("pain", 2, 1.20, "boulangerie"),
    ("lait", 1, 0.90, "laitier"),
    ("fromage", 2, 2.50, "laitier"),
    ("pomme", 2, 0.80, "fruits"),
    ("yaourt", 4, 0.60, "laitier")
]

# Uso de diccionarios para agrupar por categoría
ventes_par_categorie = {}
for produit, quantite, prix, categorie in ventes:
    if categorie not in ventes_par_categorie:
        ventes_par_categorie[categorie] = []
    ventes_par_categorie[categorie].append((produit, quantite, prix))

# Uso de conjuntos para obtener productos únicos
produits_uniques = {produit for produit, _, _, _ in ventes}
print(f"Produits uniques: {produits_uniques}")  # {'pain', 'pomme', 'fromage', 'lait', 'yaourt', 'banane'}

# Uso de tuplas para almacenar totales por categoría (inmutable)
totaux_par_categorie = tuple(
    (categorie, sum(quantite * prix for _, quantite, prix in produits))
    for categorie, produits in ventes_par_categorie.items()
)
print("Totaux par catégorie:", totaux_par_categorie)

# Uso de listas y comprensiones para analizar las ventas
total_par_produit = {}
for produit, quantite, prix, _ in ventes:
    if produit in total_par_produit:
        total_par_produit[produit] = (total_par_produit[produit][0] + quantite, prix)
    else:
        total_par_produit[produit] = (quantite, prix)

# Lista ordenada de productos por cifra de negocio
ca_par_produit = [(produit, quantite * prix) for produit, (quantite, prix) in total_par_produit.items()]
ca_par_produit.sort(key=lambda x: x[1], reverse=True)

print("Produits par chiffre d'affaires:")
for produit, ca in ca_par_produit:
    print(f"- {produit}: {ca:.2f}€")

Rendimiento de las estructuras de datos

Para aplicaciones que manipulan grandes cantidades de datos, el rendimiento importa. Aquí un resumen de las complejidades temporales de las operaciones habituales:

OperaciónListaTuplaDiccionarioConjunto
Acceso por índiceO(1)O(1)N/AN/A
Acceso por claveN/AN/AO(1)¹N/A
Búsqueda de elementoO(n)O(n)O(1)¹O(1)¹
Añadir elementoO(1)²N/AO(1)¹O(1)¹
Eliminar elementoO(n)N/AO(1)¹O(1)¹

¹ En promedio. En el peor caso (raro), estas operaciones pueden ser O(n).
² Añadir al final es O(1) amortizado. La inserción en el medio es O(n).

Conclusión

Las estructuras de datos son los bloques de construcción fundamentales de todo programa Python. Comprender sus características, ventajas e inconvenientes te ayudará a escribir un código más eficaz y elegante.

Para recapitular:

  • Las listas son versátiles y modificables, perfectas para colecciones ordenadas
  • Las tuplas son inmutables y eficientes, ideales para datos de solo lectura
  • Los diccionarios ofrecen búsquedas rápidas por clave, perfectos para asociaciones
  • Los conjuntos eliminan duplicados y permiten operaciones de conjuntos eficaces

Elegir la estructura adecuada para cada situación es una habilidad que mejora con la práctica. No dudes en experimentar con distintos enfoques para resolver tus problemas de datos.

En el próximo tutorial exploraremos las funciones en Python y cómo usarlas para organizar y reutilizar tu código con eficacia.


¿Necesitas repasar las bases de Python? Consulta nuestro tutorial sobre las bases de la sintaxis Python.

Comentarios

Los comentarios funcionan con GitHub Discussions

Inicia sesión con GitHub para participar en la discusión

¡Enlace copiado!