Un set, también llamado conjunto, es una colección de elementos desordenados que no admite duplicados. Se trata, por tanto, de una estructura de datos equivalente a los conjuntos en matemáticas. Además, como sucede con los elementos de las listas o las claves de los diccionarios, los elementos de un set no necesariamente han de ser del mismo tipo. En este post vamos a ver a fondo cómo utilizar los sets en Python.
Creación de sets
En Python los sets se pueden crear de dos formas distintas. Por un lado, usando llaves ({}) y separando sus elementos con comas (,) como se muestra a continuación:
>>> numeros = {"uno", 2, 3.1415} >>> numeros {'uno', 2, 3.1415}
Alternativamente, podemos usar el constructor set al que le tenemos que pasar una lista con los elementos del set:
>>> numeros = set(["uno", 2, 3.1415]) >>> numeros {'uno', 2, 3.1415}
Para crear un set vacío, es decir sin elementos, sólo podemos hacerlo mediante el constructor ya que si lo hacemos con las llaves Python lo interpreta como un diccionario.
>>> numeros = set() >>> numeros set() >>> numeros = {} >>> type(numeros) <class 'dict'>
Al principio del post hemos dicho que los sets no admiten elementos duplicados. Efectivamente, si intentamos añadir elementos duplicados a un set Python los ignora.
>>> numeros = {"uno", 2, 3.1415, "uno", 2, 3.1415} >>> numeros {'uno', 2, 3.1415}
Acceder a los elementos de un set
En Python solemos usar los corchetes ([]) para acceder a los elementos de una estructura de datos. Por ejemplo, en las listas indicamos el índice (o posición) que ocupa el elemento en la lista. Sin embargo, los sets son colecciones de elementos desordenados que no están indexados. Por tanto, si intentamos acceder a sus elementos como lo haríamos en una lista obtenemos un error de tipo TypeError
.
>>> numeros[0] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'set' object is not subscriptable
En su lugar, para acceder a los elementos de un set tenemos que recurrir a un bucle for.
>>> for elemento in numeros: ... print(elemento) ... uno 2 3.1415
Alternativamente, también podemos comprobar si cierto elemento pertenece a un set mediante la palabra clave in.
>>> "uno" in numeros True >>> "dos" in numeros False
En este punto cabe destacar que la operación de testear la pertenencia de un elemento es más eficiente en los sets que en las listas. En concreto, la complejidad temporal de esta operación en sets es de O(1), es decir, constante sea cual sea el número de elementos de set. Por el contrario, testear la pertenencia de un elemento en una lista tiene una complejidad temporal de O(n), que significa que aumenta linealmente con el número de elementos de la lista. Por tanto, si tenemos que almacenar grandes cantidades de elementos en una estructura de datos y sabemos que esos elementos son únicos, sería preferible utilizar un set antes que una lista para que nuestro código sea más eficiente.
Añadir y eliminar elementos a un set
Para añadir un nuevo elemento a un set tenemos el método add()
. Sin embargo, recordemos que los sets no admiten elementos duplicados, por tanto el método add()
sólo añade el elemento si éste no se encuentra dentro del set, tal y como se muestra a continuación:
>>> numeros {'uno', 2, 3.1415} >>> numeros.add(2) >>> numeros {'uno', 2, 3.1415} >>> numeros.add("cuatro") >>> numeros {'cuatro', 2, 3.1415, 'uno'}
Si lo deseamos, podemos añadir varios elementos de golpe con el método update()
, el cual utiliza una lista como parámetro de entrada.
>>> numeros.update([5, 6.283]) >>> numeros {'cuatro', 2, 3.1415, 5, 6.283, 'uno'}
Para eliminar elementos de un set existen dos métodos principales que son remove()
y discard()
.
>>> numeros {'cuatro', 2, 3.1415, 5, 6.283, 'uno'} >>> numeros.remove(6.283) >>> numeros.discard(5) >>> numeros {'cuatro', 2, 3.1415, 'uno'}
La diferencia entre estos dos métodos radica en que el método remove()
lanza un error de tipo KeyError
si el elemento que intentamos eliminar no se encuentra el set. Por el contrario, el método discard()
no hace nada si intentamos eliminar un elemento que no pertenece al set.
>>> numeros {'cuatro', 2, 3.1415, 'uno'} >>> numeros.remove(5) Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 5 >>> numeros.discard(5) >>> numeros {'cuatro', 2, 3.1415, 'uno'}
Pero los métodos remove()
y discard()
no son los únicos que nos permiten eliminar elementos de un set. En ciertos casos nos puede interesar eliminar un elemento aleatorio de un set. Para ello existe el método pop()
, el cual retorna el elemento extraído del set.
>>> numeros {'cuatro', 2, 3.1415, 'uno'} >>> numeros.pop() 'cuatro' >>> numeros {2, 3.1415, 'uno'}
Otra posibilidad es eliminar todos los elementos del set de golpe, es decir, dejarlo vacío. Para ello podemos usar el método clear()
.
>>> numeros {2, 3.1415, 'uno'} >>> numeros.clear() >>> numeros set()
Operaciones entre sets
Donde podemos sacar mayor partido a los sets es cuando aplicamos las operaciones que vamos a ver a continuación. Para ello vamos a utilizar los siguientes sets como ejemplos.
>>> impares = {1, 3, 5, 7, 9} >>> primos = {2, 3, 5, 7}
Unión
La unión dos conjuntos retorna un conjunto que contiene todos los elementos pertenecientes a alguno de los dos conjuntos. En Python esta operación se puede realizar mediante la barra vertical (|) o el método union()
.
>>> impares | primos {1, 2, 3, 5, 7, 9} >>> impares.union(primos) {1, 2, 3, 5, 7, 9}
Intersección
La intersección de dos conjuntos es un conjunto que contiene los elementos que pertenecen a ambos conjuntos. En Python se realiza con el símbolo ampersand (&) o el método intersection()
.
>>> impares & primos {3, 5, 7} >>> impares.intersection(primos) {3, 5, 7}
Diferencia
La diferencia entre un conjunto A y un conjunto B es el resultado de eliminar del conjunto A cualquier elemento presente en B. Por tanto, el orden en el que se realiza la operación es significativo tal y como es muestra en el siguiente ejemplo. En Python podemos calcular la diferencia entre dos conjuntos mediante el signo menos (-) o el método difference()
.
>>> impares - primos {1, 9} >>> impares.difference(primos) {1, 9} >>> primos.difference(impares) {2}
Diferencia simétrica
La diferencia simétrica entre dos conjuntos comprende todos los elementos que pertenecen a uno de los dos conjuntos, pero no a ambos a la vez. Esta operación se puede realizar en Python mediante el acento circunflejo (^) o el método symmetric_difference()
.
>>> impares ^ primos {1, 2, 9} >>> impares.symmetric_difference(primos) {1, 2, 9}
En la siguiente imagen podemos ver una representación gráfica de estas cuatro operaciones.
Otras operaciones con sets
Como sucede con otras estructuras de datos, podemos usar la función len()
para calcular el número de elementos de un set.
>>> numeros = {"uno", 2, 3.1415} >>> len(numeros) 3
Otra operación interesante que podemos realizar utilizando sets es remover los elementos duplicados de una lista. Si no usamos sets probablemente recorreríamos la lista en un bucle, e iríamos añadiendo cada elemento a otra lista después de haber comprobado su pertenencia. Sin embargo, esta operación es mucho más sencilla si primero convertimos nuestra lista en un set y luego reconvertimos el resultado a una lista tal y como se muestra en el siguiente fragmento de código.
>>> milista = [1, 1, 2, 2, 3, 3] >>> milista = list(set(milista)) >>> milista [1, 2, 3]