Pular para o conteúdo principal

Sets

Teoria dos conjuntos:

teoria dos conjuntos

Python tem um tipo de objeto para representar este tipo composto, as características de uso são bastante similares com listas e tuplas, mas é um objeto bastante particular com usos específicos.

Sets podem ser criados usando as sintaxes:

# A partir de qualquer objeto iterável
iteravel = [1, 2, 3] # list
iteravel = 1, 2, 3 # tuple
iteravel = "Banana" # str

# usando a classe
set(iteravel)

# usando literais com { e }
{1, 2, 3, 4}

# desempacotando tuplas, listas ou textos
{*iteravel}

Aplicamos a teoria dos conjuntos usando operadores

>>> conjunto_a = [1, 2, 3, 4, 5]
>>> conjunto_b = [4, 5, 6, 7, 8]

# | para união
>>> set(conjunto_a) | set(conjunto_b)
{1, 2, 3, 4, 5, 6, 7, 8}

# & para intersecção
>>> set(conjunto_a) & set(conjunto_b)
{4, 5}

# – para diferença
>>> set(conjunto_a) - set(conjunto_b)
{1, 2, 3}

# para ^ diferença simétrica
>>> set(conjunto_a) ^ set(conjunto_b)
{1, 2, 3, 6, 7, 8}

Interessante, mas você pode estar se perguntando onde usar isso?

Pensa numa rede social como o twitter, no conjunto A estao as pessoas que você segue, no conjunto B estão as que te seguem de volta, com este objeto você consegue determinar rapidamente quem não te segue de volta.

Você pode também usar set para determinar quais seguidores você e algum amigo tem em comum na mesma rede social.

Performance

Fazer buscar em sequências é uma operação bastante pesada, imagina que no seu twitter você tem 5000 seguidores e você deseja buscar um deles ou fazer essas operações de comparação como fizemos com os conjuntos.

Se você tiver uma lista ["joao", "bruno", "maria", ...] contendo os elementos, e quiser, por exemplo, buscar pelo usuario "alfredo" o python vai ter que percorrer toda a lista e comparar elemento por elemento até encontrar o alfredo, e se o alfredo estiver no final? Vai demorar muito, essa é uma operação com uma complexidade algorítmica O(n) pois Python vai ter que efetuar uma comparação para cada item n da lista.

Os sets implementam uma hash table! 🎉

É como se eles tivessem um indice gravado neles com uma tabela invertida dizendo

"joao" -> "esta na posição 0"
"alfredo" -> "esta na posicao 345"

Portanto, quando precisarmos buscar o alfredo o python olha primeiro essa tabela e já vai diretamente na informação que está em 345 como se fizéssemos users[345] em uma lista e a complexidade desta operação passa a ser O(1) pois agora só tem uma comparação a ser feita.

Estamos super simplificando a ideia, tem mais detalhes internos nessa implementação.

Por que isso importa? Sets são mais rápidos!

Operações como if "alfredo" in usuarios: e se usuarios for um set irá ser bem mais rápido do que caso usuarios seja uma lista ou tupla.

Mutabilidade

Você pode criar um conjunto vazio e ir adicionando elementos e também pode remover elementos, eles são mutáveis:

>>> a = set([1,2,3])
>>> a.add(4)
>>> a.remove(1)
>>> print(a)
{2, 3, 4}

Deduplicação

Esta é uma das características mais interessantes dos sets e talvez a sua maior utilidade, sets não permitem itens duplicados, então ao criar um set você elimina as duplicidades.

>>> conjunto = set()
>>> conjunto.add("Bruno")
>>> conjunto.add("Maria")
>>> conjunto.add("Bruno")
>>> conjunto.add("Maria")
>>> conjunto.add("Bruno")
>>> conjunto.add("Bruno")
>>> conjunto.add("Bruno")
>>> conjunto.add("Bruno")

# Digamos que por algum motivo (ou engano) adicionou o mesmo item mais de
uma vez
# sem problemas :)

>>> print(conjunto)
{'Bruno', 'Maria'}

# E isso também funciona em tempo de atribuição
>>> {1, 2, 3, 1, 1, 1, 1, 5, 5, 5, 5}
{1, 2, 3, 5}

Desvantagens dos sets?

  • Não respeitam a ordem de inserção, os elementos são ordenados automaticamente
  • Não permitem subscrição para acesso aos valores

Ou seja, você não pode fazer set[0] para acessar o primeiro elemento.

>>> conjunto = {4, 5, 6, 7, 8}

conjunto[0]
---------------------------------------------
TypeError Traceback (most recent call last)
Input In [60], in <module>
----> 1 conjunto[0]

TypeError: 'set' object is not subscriptable

Mas você pode usar in ou converter o set em uma lista.

>>> 4 in conjunto
True

list(conjunto)[0]
4