Um set em Python é uma coleção de itens únicos (distintos).
Python provê formas eficientes e convenientes para criação e manipulação de sets. Nesta seção aprenderemos as principais características e funcionalidades dessa poderosa estrutura de dados.
Como criar um set em Python
Python nos permite criar sets de várias formas. Uma das mais formas mais frequentemente usadas é criar um set a partir de uma lista de elementos.
# Exemplo de criação de sets.
numeros = [1, 2, 2, 3, 3, 3]
numeros_distintos = set(numeros)
print("Números: ", numeros)
print("Números distintos: ", numeros_distintos)
Números: [1, 2, 2, 3, 3, 3]
Números distintos: {1, 2, 3}
Outra forma de criarmos sets em Python é criar um conjunto vazio e inserir elementos nele à medida que desejarmos. Vejamos um exemplo.
# Exemplo de criação de sets.
numeros = [1, 2, 2, 3, 3, 3]
numeros_distintos = set() # Cria um conjunto vazio
for num in numeros:
numeros_distintos.add(num)
print("Números: ", numeros)
print("Números distintos: ", numeros_distintos)
Números: [1, 2, 2, 3, 3, 3]
Números distintos: {1, 2, 3}
Pontos importantes sobre o código acima:
numeros_distintos = set()
cria um conjunto vazio.numeros_distintos.add(num)
adiciona um elemento ao conjunto criado anteriormente. Se o elemento não existir no conjunto, ele é adicionado. Caso contrário, o elemento é simplesmente descartado (não é inserido, uma vez que já está presente no conjunto).
Um outro ponto importante a ser discutido é a diferença de inserção de elementos em listas e conjuntos.
Para inserir um elemento em uma lista, podemos usar a função insert
ou a função append
, mas para inserir um elemento em um set podemos usar somente a função add
. Essa diferença decorre do fato de que em uma lista temos um controle da posição dos elementos: insert
nos permite inserir um elemento em uma posição específica da lista e append
adiciona um elemento ao final da lista. Mas em um set
não temos controle sobre a ordem em que os elementos são armazenados. A única garantia que temos é que elementos duplicados não serão inseridos.
Além disso, ao percorrer uma lista, sabemos que os elementos serão percorridos na ordem em que foram armazenados nela, mas em um set não temos esse controle: dados dois sets com os mesmos elementos, ao percorrê-los, pode ser que a ordem dos elementos seja diferente nos dois.
Como remover elementos de um conjunto
Para remover um elemento de um conjunto em Python, podemos usar a função remove
ou a função discard
.
Os exemplos abaixo mostram o uso dessas funções.
nums = set([1, 2, 2, 3, 3, 3])
nums.remove(2)
print("Números: ", nums)
Números: {1, 3}
A função remove
deve ser usada somente se tivermos certeza que o elemento está presente no conjunto, pois se o elemento não estiver presente, a função remove
causa uma exceção, como mostramos abaixo.
nums = set([1, 2, 2, 3, 3, 3])
nums.remove(4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 4
Uma alternativa à função remove
é a função discard
, que remove um elemento do conjunto se o elemento estiver presente mas não faz nada caso o elemento não pertença ao conjunto.
Vejamos um exemplo.
nums = set([1, 2, 2, 3, 3, 3])
nums.discard(4)
nums.discard(2)
print(nums)
{1, 3}
Note que, apesar de 4
não estar presente no conjunto, nenhum erro é retornado ao tentarmos removê-lo.
Além disso, Python nos permite remover todos os elementos de um conjunto de uma vez. Para isso precisamos usar a função clear
, como mostrado no exemplo abaixo.
nums = set([1, 2, 2, 3, 3, 3])
print("Números: ", nums)
nums.clear()
print("Números: ", nums)
Números: {1, 2, 3}
Números: set()
- ⚠️ CUIDADO
-
A notação
set()
é a forma de Python indicar um conjunto vazio. Talvez você estivesse esperando ver{}
impresso aqui, mas{}
é a forma que Python usa para indicar um dicionário vazio. Por isso, para evitar confusão, quando imprimimos um conjunto vazio, Python imprimeset()
ao invés de{}
. Porém, quando o conjunto possui elementos, Python imprime{elem1, elem2, ...}
. Isso é um pouco confuso, mas é importante ter essas nuances em mente.
Operações matemáticas com sets
Sets em Python podem parecer restritos, mas eles são estruturas de dados incrívelmente úteis e são muito bons naquilo que se propõem a fazer: armazenar elementos distintos.
Um set em Python pode ser visto como uma representação de um conjunto na matemática. E assim como na matemática, em que temos união, interseção e diferença de conjuntos (além de outras operações), em Python podemos realizar essas mesmas operações em sets de forma muito eficiente.
Como exemplo, considere a operação de união de conjuntos na matemática. Suponha que tenhamos dois conjuntos $A = {0, 1, 3, 5, 7, 9}$ e $B = {0, 2, 4, 6, 8}$ e desejamos construir um conjunto $C$ que é a união dos conjuntos $A$ e $B$. Matematicamente, temos que:
$C = A \cup B = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}$.
Note que o $0$ aparece em ambos conjuntos, mas aparece uma única vez no conjunto $C$.
Em Python, podemos realizar a operação acima da seguinte forma:
A = {0, 1, 3, 5, 7, 9}
B = {0, 2, 4, 6, 8}
C = A.union(B)
print(C)
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Alternativamente, podemos realizar a operação acima de forma mais concisa, fazendo como mostrado no exemplo abaixo.
A = {0, 1, 3, 5, 7, 9}
B = {0, 2, 4, 6, 8}
C = A | B
print(C)
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Outra operação comum em conjuntos é a interseção, que nos retorna os elementos que aparecem em ambos conjuntos. O exemplo abaixo ilustra essa operação.
A = {0, 1, 3, 5, 7, 9}
B = {0, 2, 4, 6, 8}
C = A & B # Equivalente a C = A.intersect(B)
print(C)
{0}
Python nos permite realizar muitas outras operações com conjuntos. Na tabela abaixo resumimos as principais.
Operações matemáticas em sets
Símbolo matemático | Operador Python | Descrição |
---|---|---|
$e \in S$ | in |
elemento $e$ é membro de $S$ |
$A \subseteq B$ | <= |
$A$ é um subconjunto de $B$ |
$A \subset B$ | < |
$A$ é um subconjunto próprio de $B$ |
$A \cup B$ | | |
$A$ união com $B$ |
$A \cap B$ | & |
$A$ interseção com $B$ |
$A \setminus B$ | - |
Diferença entre $A$ e $B$ |
Set comprehensions
Assim como as list comprehensions, as set comprehensions fornecem uma forma eficiente e legível de gerar conjuntos de elementos com base em uma expressão e, opcionalmente, uma ou mais condições.
A sintaxe básica de uma set comprehension é semelhante à de uma list comprehension, mas utiliza chaves ({}
) em vez de colchetes ([]
). A estrutura geral é a seguinte:
conjunto = {expressao for elemento in sequencia if condicao}
A condicao
acima é opcional. Ela é usada para filtrar elementos ao construir o conjunto. Vejamos um exemplo sem o uso da condição e um exemplo com o uso dela.
Nosso primeiro exemplo consiste da identificação de palavras únicas em uma frase.
palavras = ["mundo", "mundo", "vasto", "mundo"]
palavras_unicas = {p for p in palavras}
print(palavras_unicas)
{'vasto', 'mundo'}
Vejamos agora alguns exemplos para ilustrar o uso de set comprehensions com condições de filtragem dos elementos:
numeros = [1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 10, 10]
# Números pares usando list comprehensions
numeros_pares_lista = [x for x in numeros if x % 2 == 0]
print(numeros_pares_lista)
# Números pares usando set comprehensions
numeros_pares_set = {x for x in numeros if x % 2 == 0}
print(numeros_pares_set)
{2, 4, 4, 6, 8, 10, 10, 10}
{2, 4, 6, 8, 10}
Note que a notação de set comprehensions nos permite criar o conjunto já descartando elementos duplicados, o que não acontece com as listas.
Exercícios
- Escreva uma função que recebe uma lista de elementos e retorne a quantidade de elementos únicos (distintos) na lista.
Clique para ver a solução
def num_elementos_distintos(elementos):
return len(set(elementos))
num_elementos_distintos([1, 2, 2, 3, 3, 3, 4, 4, 4, 4,])
4
- Escreva uma função que recebe uma lista de elementos e retorne a quantidade de elementos duplicados na lista.
Clique para ver a solução
def num_elementos_duplicados(elementos):
return len(elementos) - len(set(elementos))
num_elementos_duplicados([1, 2, 2, 3, 3, 3, 4, 4, 4, 4,])
6
- Escreva uma função que recebe uma string e retorna
True
se é possível converter a string para um número e obter um número válido. Por exemplo, ao convertermos a string “-123” para um número, obtemos $-123$, que é um número válido. Por outro lado, não é possível converter a string “12 3” para um número e obter um número válido, por causa do caractere de espaço presente na string. Para efeitos deste exercício, strings que começam com zero não geram números válidos, exceto se a string for simplesmente “0”.
Clique para ver a solução
Este exercício pode ser bastante complicado se tentarmos fazer uma solução avaliando todos os casos possíveis. Porém, a solução fica bem simples se tivermos em mente que quando escrevemos um número válido, existe um conjunto de caracteres que são permitidos. A ideia então é simplesmente verificar se a string de entrada possui somente caracteres permitidos.
def possivel_converter_versao_simples(s):
if s.startswith("0") and s != "0":
return False
chars_permitidos = set("0123456789-.")
for c in set(s):
if not c in chars_permitidos:
return False
return True
possivel_converter_versao_simples("0")
possivel_converter_versao_simples("01")
possivel_converter_versao_simples("12.2")
possivel_converter_versao_simples("12 3")
possivel_converter_versao_simples("+432")
possivel_converter_versao_simples("432 ")
True
False
True
False
False
False
Podemos também usar as operações de conjunto que aprendemos nesta seção para escrever uma versão mais concisa do código. A ideia aqui é que a string de entrada precisa ser um subconjunto dos caracteres permitidos para que seja possível convertê-la em um número válido.
def possivel_converter(s):
if s.startswith("0") and s != "0":
return False
chars_permitidos = set("0123456789-.")
return set(s) <= chars_permitidos
possivel_converter("0")
possivel_converter("01")
possivel_converter("12.2")
possivel_converter("12 3")
possivel_converter("+432")
possivel_converter("432 ")
True
False
True
False
False
False