Conjuntos en Python
Este post fue migrado de un blog hecho con Wordpress. Si se ve mal, dejame un comentario y lo arreglo.
Cuando estaba preparando mi charla introductoria a Python, le pasé mis slides a un amigo para que me diga su opinión y una de las cosas que me dijo fue
Nunca senti que set sea algo nativo de python, le daria mas importancia a los diccionarios, aunque tal vez tu publico este mas interesado en sets, no lo se.
Me sorprendió el comentario. Para mi, set es un tipo de dato muy útil y poderoso. En este post voy a intentar hacer una apología de set, el tipo de dato que incorpora Python para representar la noción matemática de conjunto.
Presentación
Un objeto set es una colección sin orden de objetos hasheables. Puede contener objetos de todos los tipos inmutables de Python, pero no los contenedores mutables como listas. También puede contener objetos de clases definidas por el usuario (Los objetos instancias de clases definidas por el usuario son por defecto hasheables.).
Los conjuntos se pueden crear, por ejemplo, a partir de una lista. Podemos quitar elementos (al azar o uno en concreto) o agregarlos:
>>> heladera = ['huevo', 'huevo', 'queso', 'leche', 'pera', 'pera', 'pera'] >>> alimentos = set(heladera) >>> alimentos set(['queso', 'leche', 'huevo', 'pera']) >>> alimentos.pop() 'queso' >>> alimentos.remove('leche') >>> alimentos set(['huevo', 'pera']) >>> alimentos.add('empanada') >>> alimentos set(['empanada', 'huevo', 'pera'])
Prueba de pertenencia
Otra función muy común y útil es probar la pertenencia de objetos al conjunto:
>>> 'empanada' in alimentos True >>> 'leche' in alimentos False >>> 'leche' not in alimentos True
Iterar sobre conjuntos
Podemos interar sobre conjuntos de la misma forma que lo hacemos sobre listas:
>>> for a in alimentos: ... "Debo comer " + a ... 'Debo comer empanada' 'Debo comer huevo' 'Debo comer pera'
Operaciones sobre conjuntos
Los conjuntos en Python soportan las operaciones típicas de conjuntos: restas, intersección, unión y diferencia simétrica (los elementos que están en uno de los conjuntos, pero no en ambos). Repasar operaciones con conjuntos.
>>> frutas = set(['banana', 'naranja', 'pera']) >>> frutas - alimentos set(['banana', 'naranja']) >>> alimentos - frutas set(['huevo', 'empanada']) >>> frutas & alimentos set(['pera']) >>> frutas | alimentos set(['huevo', 'empanada', 'pera', 'banana', 'naranja']) >>> frutas ^ alimentos set(['huevo', 'empanada', 'banana', 'naranja'])
También podemos preguntar sin un conjunto es subconjunto de otro. En los ejemplos se utiliza set()
, el conjunto vacío:
>>> alimentos < set() False >>> set() < alimentos True >>> set() > alimentos False >>> alimentos <= alimentos True
El problema de las dos comisiones
Este problema está basado en un caso real y lo escuché en la charla Escribí menos código, pensá como un (buen) matemático de Gustavo Carmona (FCEYN - UBA) bio y Matías A Graña (FCEyN - UBA) bio.
Se tienen dos archivos de textos con una lista de e-mails en cada uno. Cada archivo tiene los mails de los funcionarios de una comisión; los archivos no están bien depurados, por lo que pueden contener direcciones repetidas; hay funcionarios trabajando en las dos comisiones. Luego de una reunión en la que trabajaron ambas comisiones, se generó un material que se necesita enviar a todos los participantes. ¿Cómo obtener la lista de destinatarios?
archivo1 dir1@mail.com dir2@mail.com dir3@mail.com dir1@mail.com
archivo2 dir21@mail.com dir23@mail.com dir3@mail.com dir1@mail.com
Queremos una tercera lista que tenga la primera más la segunda, pero que no estén repetidos.
El enfoque tradicional que utilizaría un programador para resolver este problema mediante bucles es:
def unionlarga(l1, l2): l3 = [] for x in l1: if not x in l3: l3.append(x) for x in l2: if not x in l3: l3.append(x) return l3
Supongamos que ya tenemos los archivos leídos y almacenamos el contenidos en listas:
>>> unionlarga(archivo1, archivo2) ['dir1@mail.com', 'dir2@mail.com', 'dir3@mail.com', 'dir21@mail.com', 'dir23@mail.com']
La solución es genérica para cualquier lenguaje. Sin embargo, puede lograr una mejor solución utilizando sets en Python:
>>> list(set(archivo1) | set(archivo2)) ['dir21@mail.com', 'dir3@mail.com', 'dir2@mail.com', 'dir1@mail.com', 'dir23@mail.com']
Convertimos ambas listas a conjuntos (con lo que se eliminan los repetidos dentro de las listas), realizamos la unión de ambos conjuntos (con lo que se eliminan los repetidos entre listas y finalmente se convierte el resultado en una nueva lista.
Comentarios
Comments powered by Disqus