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.

Más sobre conjuntos en la referencia del lenguaje.

Comentarios

Comments powered by Disqus