Introducción
Contenido de la lección.
Objetivos de aprendizaje
- Objetivo 1
- Objetivo 2
- Objetivo 3
Objetivos de Aprendizaje
Al finalizar este tema, serás capaz de:
- Comprender la estructura y características de los conjuntos en Python
- Dominar las operaciones matemáticas de conjuntos (unión, intersección, diferencia)
- Aplicar conjuntos para eliminar duplicados y optimizar algoritmos
- Implementar soluciones profesionales usando sets en casos reales
📚 Conceptos Fundamentales de Conjuntos
Los conjuntos en Python son colecciones mutables de elementos únicos y no ordenados. Se crean usando llaves {} o la función set(). Las características principales incluyen: elementos únicos (no duplicados), no tienen orden específico, son mutables (se pueden modificar), y permiten solo elementos hashables (inmutables). Los conjuntos vacíos se crean con set(), no con {} (que crea un diccionario vacío). La teoría matemática de conjuntos se aplica directamente: cada elemento existe una sola vez, y las operaciones siguen las reglas algebraicas tradicionales.
# Diferentes formas de crear conjuntos
conjunto1 = {1, 2, 3, 4, 5}
conjunto2 = set([1, 2, 2, 3, 4, 4, 5])
conjunto_vacio = set()
print('Conjunto 1:', conjunto1)
print('Conjunto 2:', conjunto2)
print('Conjunto vacío:', conjunto_vacio)
print('Tipo:', type(conjunto1))
Conjunto 1: {1, 2, 3, 4, 5} Conjunto 2: {1, 2, 3, 4, 5} Conjunto vacío: set() Tipo:
# Operaciones básicas
conjunto = {1, 2, 3}
# Agregar elementos
conjunto.add(4)
print('Después de add(4):', conjunto)
# Agregar múltiples elementos
conjunto.update([5, 6, 7])
print('Después de update([5,6,7]):', conjunto)
# Eliminar elemento
conjunto.remove(7)
print('Después de remove(7):', conjunto)
# Verificar pertenencia
print('¿3 está en el conjunto?', 3 in conjunto)
Después de add(4): {1, 2, 3, 4} Después de update([5,6,7]): {1, 2, 3, 4, 5, 6, 7} Después de remove(7): {1, 2, 3, 4, 5, 6} ¿3 está en el conjunto? True
🎯 Operaciones Matemáticas de Conjuntos
Python implementa las operaciones matemáticas clásicas de conjuntos: unión (|), intersección (&), diferencia (-), y diferencia simétrica (^). Estas operaciones tienen equivalentes en métodos: union(), intersection(), difference(), y symmetric_difference(). La unión combina elementos de ambos conjuntos, la intersección encuentra elementos comunes, la diferencia obtiene elementos del primer conjunto que no están en el segundo, y la diferencia simétrica encuentra elementos que están en uno u otro conjunto, pero no en ambos. Estas operaciones son fundamentales en algoritmos de análisis de datos y lógica computacional.
# Definir conjuntos para operaciones
A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}
# Unión
union = A | B
print('A ∪ B:', union)
# Intersección
interseccion = A & B
print('A ∩ B:', interseccion)
# Diferencia
diferencia = A - B
print('A - B:', diferencia)
# Diferencia simétrica
dif_simetrica = A ^ B
print('A ⊕ B:', dif_simetrica)
A ∪ B: {1, 2, 3, 4, 5, 6, 7, 8} A ∩ B: {4, 5} A - B: {1, 2, 3} A ⊕ B: {1, 2, 3, 6, 7, 8}
# Usando métodos en lugar de operadores
A = {1, 2, 3, 4}
B = {3, 4, 5, 6}
# Métodos equivalentes
print('Union method:', A.union(B))
print('Intersection method:', A.intersection(B))
print('Difference method:', A.difference(B))
# Relaciones entre conjuntos
C = {1, 2}
print('¿C es subconjunto de A?', C.issubset(A))
print('¿A es superconjunto de C?', A.issuperset(C))
print('¿A y B son disjuntos?', A.isdisjoint(B))
Union method: {1, 2, 3, 4, 5, 6} Intersection method: {3, 4} Difference method: {1, 2} ¿C es subconjunto de A? True ¿A es superconjunto de C? True ¿A y B son disjuntos? False
💡 Eliminación de Duplicados y Optimización
Una aplicación fundamental de los conjuntos es la eliminación eficiente de duplicados en colecciones de datos. Los sets proporcionan la forma más rápida de eliminar duplicados manteniendo elementos únicos. Esta técnica es crucial en preprocessing de datos, limpieza de datasets, y optimización de algoritmos. Los conjuntos también mejoran el rendimiento en operaciones de búsqueda y pertenencia comparado con listas, especialmente en grandes volúmenes de datos. La conversión lista->set->lista es un patrón común para eliminar duplicados, aunque no preserva el orden original.
# Lista con duplicados
lista_duplicados = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5]
print('Lista original:', lista_duplicados)
# Eliminar duplicados
sin_duplicados = list(set(lista_duplicados))
print('Sin duplicados:', sin_duplicados)
# Con strings
palabras = ['python', 'java', 'python', 'c++', 'java', 'go']
palabras_unicas = list(set(palabras))
print('Palabras originales:', palabras)
print('Palabras únicas:', palabras_unicas)
# Preservar orden (Python 3.7+)
from collections import OrderedDict
con_orden = list(OrderedDict.fromkeys(lista_duplicados))
print('Sin duplicados con orden:', con_orden)
Lista original: [1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5] Sin duplicados: [1, 2, 3, 4, 5] Palabras originales: ['python', 'java', 'python', 'c++', 'java', 'go'] Palabras únicas: ['python', 'java', 'c++', 'go'] Sin duplicados con orden: [1, 2, 3, 4, 5]
# Comparación de rendimiento en búsquedas
import time
# Crear datos de prueba
lista_grande = list(range(10000)) * 2 # Lista con duplicados
conjunto_grande = set(lista_grande)
# Función para medir tiempo
def medir_busqueda(estructura, elemento):
start = time.time()
resultado = elemento in estructura
end = time.time()
return resultado, (end - start) * 1000
# Buscar elemento
elemento_buscar = 9999
# En lista
en_lista, tiempo_lista = medir_busqueda(lista_grande, elemento_buscar)
print(f'Búsqueda en lista: {en_lista}, Tiempo: {tiempo_lista:.4f} ms')
# En conjunto
en_conjunto, tiempo_conjunto = medir_busqueda(conjunto_grande, elemento_buscar)
print(f'Búsqueda en conjunto: {en_conjunto}, Tiempo: {tiempo_conjunto:.4f} ms')
print(f'Elementos únicos: {len(conjunto_grande)} de {len(lista_grande)} totales')
Búsqueda en lista: True, Tiempo: 0.1250 ms Búsqueda en conjunto: True, Tiempo: 0.0020 ms Elementos únicos: 10000 de 20000 totales
🔧 Casos de Uso Avanzados y Aplicaciones Profesionales
En el desarrollo profesional, los conjuntos resuelven problemas complejos de manera elegante. Se utilizan en sistemas de recomendación para encontrar intersecciones de preferencias, en análisis de logs para identificar IPs únicas, en control de acceso para verificar permisos, y en algoritmos de grafos para manejar nodos visitados. Los set comprehensions proporcionan creación eficiente de conjuntos con filtrado. La combinación de conjuntos con otras estructuras de datos crea soluciones robustas para problemas de ingeniería de software, análisis de datos, y sistemas distribuidos.
# Sistema de recomendación simple
usuarios_productos = {
'usuario1': {'laptop', 'mouse', 'teclado', 'monitor'},
'usuario2': {'laptop', 'tablet', 'mouse', 'audífonos'},
'usuario3': {'smartphone', 'tablet', 'audífonos', 'cargador'},
'usuario4': {'laptop', 'mouse', 'cargador', 'webcam'}
}
def encontrar_usuarios_similares(usuario_target, base_usuarios):
productos_target = base_usuarios[usuario_target]
similitudes = {}
for usuario, productos in base_usuarios.items():
if usuario != usuario_target:
interseccion = productos_target & productos
if interseccion:
similitudes[usuario] = len(interseccion)
return similitudes
# Encontrar usuarios similares
resultado = encontrar_usuarios_similares('usuario1', usuarios_productos)
print('Usuarios similares a usuario1:', resultado)
# Productos en común
comunes = usuarios_productos['usuario1'] & usuarios_productos['usuario2']
print('Productos en común usuario1 y usuario2:', comunes)
Usuarios similares a usuario1: {'usuario2': 2, 'usuario4': 2} Productos en común usuario1 y usuario2: {'laptop', 'mouse'}
# Simulación de análisis de logs
logs_servidor = [
'192.168.1.1 GET /home',
'192.168.1.2 POST /login',
'192.168.1.1 GET /dashboard',
'10.0.0.5 GET /api/data',
'192.168.1.2 GET /profile',
'10.0.0.5 POST /api/update',
'203.0.113.1 GET /home'
]
# Extraer IPs únicas
ips_unicas = set()
for log in logs_servidor:
ip = log.split()[0]
ips_unicas.add(ip)
print('IPs únicas que accedieron:', ips_unicas)
print('Total de accesos únicos:', len(ips_unicas))
# IPs sospechosas (ejemplo)
ips_bloqueadas = {'203.0.113.1', '198.51.100.1'}
ips_activas = ips_unicas - ips_bloqueadas
ips_peligrosas = ips_unicas & ips_bloqueadas
print('IPs activas permitidas:', ips_activas)
print('IPs bloqueadas detectadas:', ips_peligrosas)
IPs únicas que accedieron: {'192.168.1.1', '192.168.1.2', '10.0.0.5', '203.0.113.1'} Total de accesos únicos: 4 IPs activas permitidas: {'192.168.1.1', '192.168.1.2', '10.0.0.5'} IPs bloqueadas detectadas: {'203.0.113.1'}
Ejercicios Prácticos
Gestión de Inventario con Conjuntos
INTERMEDIODescripción:
Crea un sistema que gestione inventarios de múltiples almacenes. Implementa funciones para encontrar productos disponibles en todos los almacenes, productos únicos de cada almacén, y productos que necesitan reposición.
Análisis de Redes Sociales
AVANZADODescripción:
Simula una red social donde cada usuario tiene un conjunto de amigos. Implementa funciones para encontrar amigos mutuos, sugerir nuevas amistades, y detectar comunidades basadas en conexiones comunes.
Optimización de Base de Datos
INTERMEDIODescripción:
Dada una base de datos con registros duplicados, crea un algoritmo que identifique y elimine duplicados basándose en múltiples criterios (ID, email, teléfono), manteniendo estadísticas del proceso de limpieza.
Sistema de Control de Acceso
AVANZADODescripción:
Diseña un sistema de permisos donde usuarios tienen roles y cada rol tiene permisos específicos. Implementa verificación de acceso, escalamiento de privilegios, y auditoría de permisos usando operaciones de conjuntos.
Resumen y Próximos Pasos
Los conjuntos en Python son herramientas fundamentales que combinan elegancia matemática con eficiencia computacional. Dominando sus operaciones y aplicaciones, los ingenieros pueden resolver problemas complejos de manera eficiente y elegante. En el próximo tema exploraremos diccionarios, estructuras que complementan perfectamente a los conjuntos para crear soluciones de datos robustas y escalables en aplicaciones profesionales.