Conjuntos¶
Objetivos de aprendizagem¶
Descrever, em linguagem natural e em Python, os conceitos fundamentais da teoria ingênua de conjuntos;
Implementar operações entre conjuntos em Python utilizando o tipo fundamental "set";
Identificar e interpretar relações entre conjuntos de dados em contextos aplicados;
Projetar soluções computacionais básicas que utilizem estruturas de conjuntos para representar e cruzar informações
Teoria “ingênua” de conjuntos¶
A teoria ingênua de conjuntos é o ponto de partida da Matemática moderna. Ela se baseia na ideia intuitiva de que um conjunto é simplesmente uma coleção de objetos bem definidos, chamados elementos. O adjetivo ingênua é usado porque essa abordagem trata os conjuntos de forma direta, sem recorrer a formalismos lógicos rigorosos — assume-se que qualquer coleção de objetos pode formar um conjunto.
Essa visão é suficiente para aplicações práticas em ciência da computação, onde conjuntos são usados para representar grupos de dados, categorias, coleções de registros ou relações entre objetos. Ela se contrapõe à teoria axiomática, que fornece estruturas necessária para se provar propriedades fundamentais de forma rigorosa e evitar contradições. Neste capítulo, veremos como expressar a teoria ingênua a partir de exemplos usando a linguagem Python.
Princípios de intuição¶
A intuição natural sobre o que é um conjunto apoia-se em ideias pouco rigorosas. São três os princípios básicos da teoria ingênua:
Princípio da compreensão irrestrita:
“Para toda propriedade , existe um conjunto formado por todos os elementos que a satisfazem.”
Princípio da extensionalidade:
“Dois conjuntos são iguais se e somente se têm os mesmos elementos.”
Este princípio, também usado pela teoria axiomática, diz que um conjunto é definido pela “extensão” de seus elementos.
Princípio da liberdade de construção:
“Qualquer coleção de objetos bem definidos pode ser reunida em um conjunto.”
Este princípio, na verdade, apenas reforça a “ingenuidade” de se definir conjuntos de forma livre.
Elementos¶
Em Python, os elementos (ou membros) de um conjunto (finito) serão caracterizados por um objeto que possui um tipo. Aqui, usaremos os seguintes: int, float, bool, str, list, tuple e set.
Vejamos alguns exemplos:
type(2)inttype(3.5)floattype(True)booltype(False)booltype('palavra')strtype([1,'a',3.5,True])listtype((1,2))tupletype({1,2,3})setDefinição de conjuntos¶
De maneira simples, podemos definir uma coleção ou conjunto de elementos por atribuição e listas.
vogais = ['a','e','i','o','u'] # conjunto das vogais
vogais['a', 'e', 'i', 'o', 'u']P = [1,3,5,7]
P[1, 3, 5, 7]Entretanto, para usarmos operações de conjuntos, a estrutura mais adequada para definir conjuntos é set.
V = set(vogais)
V{'a', 'e', 'i', 'o', 'u'}P = set(P)
P{1, 3, 5, 7}Definição por extensão¶
Podemos definir um conjunto em Python de duas formas:
usando
set();usando um par de chaves com especificação de elementos:
{expr, expr2, ...}.
Conjunto vazio¶
# Única forma (e correta) de criar um conjunto vazio em Python
A = set()
A
set()Conjunto unitário¶
B = {1}
B{1}Conjunto arbitrário¶
C = {'a','b',1,2}
C{1, 2, 'a', 'b'}1 in CTrue'a' not in CFalseContinência¶
Considere o conjunto
D = {1,2}D <= CTrueD < CTrueC >= DTrueC > DTrueIgualdade¶
Consideremos , , , e
A = {1,4,3,1}
B = {1,4,3,3,1}
C = {4,3,1}
D = {2,1}
E = {1,2,1}A == BTrueA == CTrueD == ETrueC != DTrueB != ETrueA == B == CTrueCardinalidade¶
A cardinalidade de um conjunto é o número de elementos que ele contém.
Para sabermos o número de elementos de um set, use a função len
len(C)3Definição por propriedade¶
Em Python, podemos construir conjuntos usando compreensão de conjuntos (set comprehension), que é a forma mais próxima da notação matemática .
A sintaxe geral é:
{ expressão for variável in sequência if condição },em que sequência é um objeto iterável e condição é uma condição opcional.
F = {x for x in range(10)}
F{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}d = range(4)
e = range(6)
D = {-x for x in d[1:3]}
E = {x for x in e}
D{-2, -1}{-x for x in d[1:3]}{-2, -1}E{0, 1, 2, 3, 4, 5}B = {x for x in range(10) if x % 2 == 0}
B{0, 2, 4, 6, 8}C = {x for x in range(20) if x**2 < 100}
C{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}Elementos e conjuntos como “objetos”¶
Para representarmos elementos de um conjunto qualquer por meio do computador, é natural usarmos o conceito abstrato de “objeto”. Um objeto, na ciência da computação, é uma entidade dotada de várias propriedades que são discutadas em uma disciplina específica denominada Programação Orientada a Objetos. Por ora, vamos elencar apenas duas dessas propriedades, por serem relevantes para nosso contexto:
Identidade: propriedade que o distingue de qualquer outro objeto. Em Python usamos
id(x)para localizar o “endereço lógico” ou “etiqueta” de um objetox.Estado: propriedade de conter dados armazenados pelo objeto: atributos, valores e estruturas. O estado pode ser mutável ou imutável.
Comportamento: propriedade que permite operações e interações com outros objetos, como os métodos.
Mutabilidade de conjuntos¶
Em Python, um objeto definido como set() é mutável. Isto significa que sua estrutura interna pode ser modificada após sua criação sem troca de identidade. Vejamos um exemplo:
# Cria um conjunto S
S = {0,1,2}
# Identidade atual de S
id_atual = id(S)
# Inclui o elemento 3 em S
S.add(3)
# Identidade de S após modificação
id_nova = id(S)
# Testa se a identidade de S mudou após a modificação
print(id_atual == id_nova)True
Métodos que modificam conjuntos¶
O quadro abaixo elenca os principais métodos modificadores de um set.
| Método | Descrição |
|---|---|
add(x) | Adiciona o elemento x ao conjunto. |
remove(x) | Remove x; lança erro se x não existir. |
discard(x) | Remove x; não lança erro se x não existir. |
pop() | Remove e retorna um elemento arbitrário. |
clear() | Remove todos os elementos do conjunto. |
pares = {0,2,4,6,8} # conjunto dos números pares menores que 10
pares.add(10) # adiciona o elemento 10
print(pares)
pares.remove(4) # remove o elemento 4
print(pares)
pares.discard(12) # não gera erro
# pares.remove(12) # gera erro
print(pares.pop()) # remove e retorna um elemento arbitrário
print(pares.clear()) # esvazia o conjunto{0, 2, 4, 6, 8, 10}
{0, 2, 6, 8, 10}
0
None
Uma consequência importante da mutabilidade¶
Por serem mutáveis, um set não pode ser colocado dentro de outro set. Neste sentido, não conseguimos representar de imediato, algo como , perfeitamente aceitável na Matemática. A solução que trata essa divergência entre Matemática e Computação é frozenset, um tipo de dado que cria um conjunto imutável.
A = {frozenset({1}), frozenset({2,3})}
A{frozenset({1}), frozenset({2, 3})}A = frozenset({0,2,4,6,8}) # conjunto dos números pares menores que 10
A.add(10) # gera erro---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[41], line 2
1 A = frozenset({0,2,4,6,8}) # conjunto dos números pares menores que 10
----> 2 A.add(10) # gera erro
AttributeError: 'frozenset' object has no attribute 'add'Unicidade de conjuntos¶
Um set preserva a unicidade dos elementos. Isto significa que, internamente, ele realiza um “mapeamento” para no máximo uma ocorrência daquele elemento. Logo, set é a estrutura adequada a se usar quando não queremos repetição.
X = set() # conjunto vazio
X.add(0) # adiciona o elemento 0
X.add(0) # tenta adicionar o elemento 0 novamente
print(X) # unicidade preservada{0}
Y = {0,0,0,1,1,2,2} # exemplo de unicidade preservada
Y{0, 1, 2}Não-ordenabilidade de conjuntos¶
Um set não preserva a ordem de inserção e não permite acessar elementos por posição (indexação). Ao percorrermos um set com um laço, por exemplo, os elementos do conjunto são acessados em uma ordem que:
não depende da ordem original;
pode mudar entre execuções;
pode mudar quando o
setcresce.
# Execute este código 3 vezes, sempre limpando antes para observar a não-ordenabilidade
Y = {7, 2, 6, 3}
print(", ".join(str(y) for y in Y))
Y.add(-1)
print(", ".join(str(y) for y in Y))
Y.add(-10)
print(", ".join(str(y) for y in Y))
Y.add(-2)
print(", ".join(str(y) for y in Y))2, 3, 6, 7
2, 3, 6, 7, -1
2, 3, 6, 7, -10, -1
2, 3, 6, 7, -10, -2, -1
Casos de utilidade para set¶
Remoção de duplicatas de forma rápida:
_ = [1, 2, 2, 3, 4, 4, 4]
unicos = set(_)
unicos{1, 2, 3, 4}Testar pertinência (mais rápido que lista)
forbidden = {"H2SO4", "H2S", "H2SO3"}
if "H2S" in forbidden:
print("Item proibido!")Item proibido!
Filtragem lógica (ver Exemplo Aplicado II)
esportes = {("futebol", 22), ("tênis", 6.7), ("basquete", 24), ("pingue-pongue", 4)}
limite = 10
selecionados = {nome for (nome, d) in esportes if d < limite}
selecionados{'pingue-pongue', 'tênis'}Quadro-resumo de operações elementares¶
O quadro abaixo lista as operações elementares com conjuntos que aprendemos e como executá-las em Python.
| Operação | Símbolo matemático | Operador / Método em Python |
|---|---|---|
| Pertinência | x in A | |
| Não-pertinência | x not in A | |
| Subconjunto | A <= B | |
| Subconjunto próprio | A < B | |
| Superconjunto | A >= B | |
| Superconjunto próprio | A > B | |
| Igualdade | A == B | |
| Conjunto vazio | set() |
Exercícios aplicados resolvidos¶
I. Identificar o vocabulário único de um arquivo de texto e contar palavras.
# Conteúdo de '1-texto.txt'.
A inteligência artificial está transformando a educação e a pesquisa em ciência de dados.
A pesquisa impulsiona novas descobertas.Resolução¶
palavras = set()
with open("../examples/1-texto.txt", "r", encoding="utf-8") as f:
for linha in f:
for palavra in linha.lower().split():
palavras.add(palavra.strip(".,;!?"))
print("Vocabulário distinto:", palavras)
print("Total de palavras únicas:", len(palavras))Vocabulário distinto: {'dados', 'de', 'descobertas', 'está', 'transformando', 'impulsiona', 'artificial', 'em', 'ciência', 'novas', 'pesquisa', 'e', 'educação', 'inteligência', 'a'}
Total de palavras únicas: 15
Uma descrição matemática possível para o exemplo I é:
“Seja o conjunto de todas as palavras da Língua Portuguesa que aparecem no fragmento de texto dado e as palavras que aparecem apenas uma única vez. Determine o número de tais palavras.”
Este problema, teve como resultado o número inteiro , para , com .
II. Capturar somente os esportes cujos diâmetros das bolsas ou discos são menores que um valor limite.
Resolução¶
# Dataframe com esportes e seus diâmetros padrão (em milímetros)
dados = {
"esporte": ["Basquete", "Futebol", "Tênis", "Pingue-pongue", "Golfe", "Beisebol", "Hóquei"],
"diametro_mm": [240, 220, 67, 40, 43, 74, 76]
}
# Criação do dataframe
from pandas import DataFrame
df = DataFrame(dados)
df# Valor do limitante (em milímetros)
L = 80
# Filtragem dos esportes com diâmetro menor que L
E_L = set(df[df["diametro_mm"] < L]["esporte"])
E_L{'Beisebol', 'Golfe', 'Hóquei', 'Pingue-pongue', 'Tênis'}Uma descrição matemática possível para o exemplo II é:
“Seja o conjunto de todos os esportes registrados no banco de dados e o diâmetro da bola ou disco do esporte correspondente. Determine o subconjunto dos esportes para os quais é inferior a um valor determinado.”
Este problema, que se resume a uma filtragem, teve como resultado o conjunto para mm.