Python3 06 – Conjuntos (Set)
- Python3 01 – Iniciando…
- Python3 02 – “Variáveis”
- Python3 03 – Controle de Fluxo e Funções
- Python3 04 – Sequências: Strings e Tuplas
- Python3 05 – Sequências: Listas
- Python3 06 – Conjuntos (Set)
- Python3 07 – Dicionários
- Python3 08 – Tratamento de Exceções e Arquivos
- Python3 09 – Classes e Orientação a Objetos
- Python3 10 – Zip, Map, Reduce, Filter e Lambda
Índice
Conjuntos são um tipo especial de dados do Python com características bem específicas, principalmente para serem empregados como chaves em dicionários e bancos de dados.
1. Conjuntos (set)
Conjunto é uma estrutura de dados mutável, composto de uma coletânea de objetos hashable desordenados e com elementos únicos, ou seja, sem duplicatas. Conjuntos ainda suportam operações matemáticas de união, interseção, diferença e diferença simétrica.
Objetos hashable são todos aqueles que possuem o método __hash__()
, o qual retorna um valor inteiro constante, ou seja, o mesmo valor por toda a vida do objeto. Objetos com o mesmo hash()
são considerados idênticos quando empregados como índice. Isto ficará mais claro quando for tratado sobre a estrutura de dados dicionário. Entretanto, esta característica é indispensável para que conjuntos possam serem empregados como chaves em dicionários, como será mostrado no próximo texto1.
Um conjunto pode ser criado usando chaves ou pela função set()
, passando como elementos qualquer conjunto de objetos ou mesmo um iterável. Veja os comandos a seguir:
[xterm color=’true’ py=’true’]
>>> cesta = {‘laranja’, ‘goiaba’, ‘banana’, ‘maça’, ‘abacate’, ‘banana’, ‘goiaba’}
>>> cesta
{‘banana’, ‘abacate’, ‘goiaba’, ‘laranja’, ‘maça’}
>>> a = set(‘São Paulo’)
>>> a
{‘o’, ‘l’, ‘P’, ‘a’, ‘u’, ‘ã’, ‘S’, ‘ ‘}
>>> b = set(‘Espírito Santo’)
>>> b
{‘p’, ‘i’, ‘í’, ‘t’, ‘r’, ‘s’, ‘o’, ‘E’, ‘a’, ‘n’, ‘S’, ‘ ‘}
>>> c = {1, 2.14, ‘três’, 5j, (1,0,0)}
>>> c
{1, 2.14, (1, 0, 0), 5j, ‘três’}
[/xterm]
No primeiro conjunto, cesta
, são adicionadas diversas frutas, mas as repetidas são excluídas do conjunto. Em seguida, são criados os dois conjuntos a
e b
, com as letas das strings ‘São Paulo’ e ‘Espírito Santo’. Observe que a ordem dos elementos dos conjuntos não é a ordem de entrada, ou seja, não são ordenados. Por fim, o conjunto c
utiliza uma diversidade de tipos de objetos imutáveis, como inteiros, complexo, string, um float e uma tupla. Todos estes imutáveis são hashables e, portanto, retornam um código hash único para elementos diferentes.
[xterm color=’true’ py=’true’]
>>> for i in c:
… out = ‘hash(‘ + str(i) + ‘)’
… print(‘{0:>15} = {1}’.format(out, hash(i)))
…
hash(1) = 1
hash(2.14) = 322818021289917442
hash((1, 0, 0)) = 2528505496374819208
hash(5j) = 5000015
hash(três) = -5298805650081748838
[/xterm]
Embora conjuntos possam ser empregados em laços de repetição, ou seja, sejam iteráveis, eles também não possuem o método __getitem__()
por não serem ordenados, como em listas e tuplas, e por isto não podem ser indexados. Uma tentativa de indexar um elemento de um conjunto gera um erro TypeError
:
[xterm color=’true’ py=’true’]
>>> c[1]
Traceback (most recent call last):
File “
TypeError: ‘set’ object does not support indexing
[/xterm]
1.1. Conjuntos são Mutáveis, frozenset não
Conjuntos são objetos mutáveis e podem ter elementos adicionados e removidos através dos métodos add()
, pop()
e remove()
.
[xterm color=’true’ py=’true’]
>>> c.add(5)
>>> c.pop()
1
>>> c.pop()
2.14
>>> c.remove(‘três’)
>>> c
{5, (1, 0, 0), 5j}
[/xterm]
Explico melhor estes métodos mais adiante. Existe um tipo de conjunto que é imutável e também pode ser usado como elemento em um conjunto.
[xterm color=’true’ py=’true’]
>>> f = frozenset({2.8, 9j, ‘elf’})
>>> f
frozenset({‘elf’, 2.8, 9j})
>>> hash(f)
-8561833039905925542
>>> c.add(f)
>>> c
{5, (1, 0, 0), 5j, frozenset({‘elf’, 2.8, 9j})}
[/xterm]
FrozenSet são conjuntos imutáveis.
1.2. Operadores em Conjuntos
Conjuntos suportam um grupo específico de operadores específicos além dos operadores convencionais de comparação e operação, mas com comportamentos um pouco distintos.
Para os exemplos a seguir, considere os conteúdos dos conjuntos a
e b
como sendo o conjunto de letras nas strings ‘laranja’ e ‘marajo’, respectivamente:
[xterm color=’true’ py=’true’]
>>> a = set(‘laranja’)
>>> b = set(‘marajo’)
>>> a
{‘l’, ‘j’, ‘r’, ‘n’, ‘a’}
>>> b
{‘j’, ‘r’, ‘o’, ‘m’, ‘a’}
[/xterm]
Segue a lista de operadores:
- __and__ – mesmo que o operador
&
. Retorna a interseção dos conjuntos, ou seja, os elementos comuns entre os dois conjuntos,[xterm color=’true’ py=’true’]
>>> a.__and__(b)
{‘a’, ‘j’, ‘r’}
>>> a & b
{‘a’, ‘j’, ‘r’}
[/xterm] - __or__ – mesmo que o operador
|
. Retorna a união dos elementos contidos nos dois conjuntos,[xterm color=’true’ py=’true’]
>>> a.__or__(b)
{‘l’, ‘j’, ‘r’, ‘o’, ‘n’, ‘m’, ‘a’}
>>> a | b
{‘l’, ‘j’, ‘r’, ‘o’, ‘n’, ‘m’, ‘a’}
[/xterm] - __xor__ – o mesmo que o operador
^
. Retorna a diferença simétrica entre os dois conjuntos, ou seja, os elementos do conjuntoa
que não estão contidos no conjuntob
e os elementos deb
que não estão contidos ema
,[xterm color=’true’ py=’true’]
>>> a ^ b
{‘l’, ‘o’, ‘n’, ‘m’}
>>> a.__xor__(b)
{‘l’, ‘o’, ‘n’, ‘m’}
[/xterm] - __sub__ – operador subtração,
-
. A operaçãoa - b
retorna os elementos dea
, removidos os elementos semelhantes emb
, ou seja apenas os elementos ‘n’ e ‘l’. O contrário,b - a
retornará os elementos ‘o’ e ‘m’. Veja no exemplo abaixo:[xterm color=’true’ py=’true’]
>>> a – b
{‘n’, ‘l’}
>>> b – a
{‘o’, ‘m’}
[/xterm]Observe que a operação
(a - b) | (b - a)
é a definição dea ^ b
:[xterm color=’true’ py=’true’]
>>> (a – b) | (b – a) == (a ^ b)
True
[/xterm] - __iand__, __isub__, __ixor__, __ior__ – são implementações para os operadores
&=
,-=
,^=
e|=
, respectivamente. - __rand__, __rsub__, __rxor__, __ror__ – este ‘r’ corresponde a ‘right’. Essencialmente, implica em trocar os conjuntos de posição nas operações. Por exemplo
a.__rxor__(b) = b ^ a
, ao invés dea ^ b
. Com exceção ao operador de subtração, todos os demais retornaram o mesmo resultado.[xterm color=’true’ py=’true’]
>>> a.__rsub__(b)
{‘o’, ‘m’}
>>> a.__rand__(b)
{‘a’, ‘j’, ‘r’}
>>> a & b
{‘a’, ‘j’, ‘r’}
>>> a & b == b & a
True
>>> a – b == b – a
False
[/xterm] - __eq__, __ne__, __ge__, __gt__, __le__, __lt__ – Operadores condicionais estão definidos para conjuntos, mas operam de forma diferenciada ao visto em lista e tuplas. Como conjuntos são desordenados, os operadores de igualdade e diferença comparam os conjuntos elemento a elemento, independente da ordem que os seus elementos possam ser apresentados.
[xterm color=’true’ py=’true’]
>>> a = set(‘abacaxi’)
>>> b = set(‘xibac’)
>>> a == b
True
>>> a.add(‘f’)
>>> a == b
False
>>> a != b
True
[/xterm]Os operadores de ‘
>
‘ e ‘<
‘ correspondem aos operadores ‘contém’ e ‘está contido’ em conjuntos.[xterm color=’true’ py=’true’]
>>> a
{‘b’, ‘c’, ‘a’, ‘i’, ‘f’, ‘x’}
>>> b
{‘b’, ‘c’, ‘a’, ‘i’, ‘x’}
>>> a > b
True
>>> b < a
True
>>> a < b
False
>>> b > a
False
[/xterm]Como
b
esta contido ema
, as duas primeiras comparações (a > b
eb < a
) retornam verdadeiras, já as duas seguintes retornam falso.
[TABLE=62]
Como feito até o momento, métodos específicos a construção e atributos da classe set (conjuntos) não foram abordados, deixando este debate para adiante.
1.3. Métodos de Conjuntos
Segue os métodos dos conjuntos.
- add(Valor) – adiciona o elemento Valor ao conjunto.
[xterm color=’true’ py=’true’]
>>> a.add(5)
>>> a
{5, ‘l’, ‘j’, ‘r’, ‘a’, ‘n’}
[/xterm] - clear() – apaga todo o conteúdo do conjunto.
- copy() – cria uma cópia do conteúdo do conjunto. Como conjuntos são mutáveis, um método para fazer a sua cópia é essencial para evitar problemas como o ilustrado com as listas, no exemplo de matriz no texto anterior. Veja o exemplo:
[xterm color=’true’ py=’true’]
>>> c = a.copy()
>>> d = c
>>> c
{‘a’, 5, ‘j’, ‘l’, ‘n’, ‘r’}
>>> a
{5, ‘l’, ‘j’, ‘r’, ‘a’, ‘n’}
>>> d
{‘a’, 5, ‘j’, ‘l’, ‘n’, ‘r’}
>>> c.clear()
>>> d
set()
>>> a
{5, ‘l’, ‘j’, ‘r’, ‘a’, ‘n’}
[/xterm]Na primeira linha,
c
recebe uma cópia dea
. Jád
apenas aponta para o objeto dec
. Ao apagarc
,d
também é apagado, mas o mesmo não ocorre aa
, pois são objetos distintos na memória. - difference(set), intersection(set), union(set) e symmetric_difference(set) – estes métodos retornam o mesmo que os operadores
-
,&
,|
e^
, respectivamente.[xterm color=’true’ py=’true’]
>>> a.difference(b)
{‘l’, ‘n’, 5}
>>> a.intersection(b)
{‘j’, ‘a’, ‘r’}
>>> a.union(b)
{5, ‘l’, ‘j’, ‘r’, ‘m’, ‘o’, ‘a’, ‘n’}
>>> a.symmetric_difference(b)
{‘m’, ‘o’, 5, ‘l’, ‘n’}
[/xterm] - difference_update(set), intersection_update(set), update(set) e symmetric_difference_update(set) – estes métodos retornam o mesmo que os operadores compostos
-=
,&=
,|=
e^=
, respectivamente. Observe que o método union_update(set) não existe, é apenasupdate(set)
. - pop() – remove um elemento arbitrário do conjunto.
[xterm color=’true’ py=’true’]
>>> c
{‘m’, ‘o’, 5, ‘l’, ‘n’}
>>> c.pop()
‘m’
>>> c.pop()
‘o’
[/xterm] - remove(Valor) – remove o elemento Valor do conjunto. Se o elemento não existir, retorna o erro KeyError.
[xterm color=’true’ py=’true’]
>>> c
{5, ‘l’, ‘n’}
>>> c.remove(5)
>>> c.remove(‘n’)
>>> c.remove(3)
Traceback (most recent call last):
File ““, line 1, in
KeyError: 3
[/xterm] - discard(Valor) – remove o elemento Valor do conjunto. A única diferença com o método
remove(Valor)
é que odiscard(Valor)
não retorna erro caso o elemento não exista.[xterm color=’true’ py=’true’]
>>> c = a | b
>>> c
{5, ‘l’, ‘j’, ‘r’, ‘m’, ‘o’, ‘a’, ‘n’}
>>> c.discard(‘a’)
>>> c
{5, ‘l’, ‘j’, ‘r’, ‘m’, ‘o’, ‘n’}
>>> c.discard(3)
>>>
[/xterm] - isdisjoint(set) – retorna verdadeiro se os dois conjuntos possuem interseção nula.
[xterm color=’true’ py=’true’]
>>> c
{5, ‘l’, ‘j’, ‘r’, ‘m’, ‘o’, ‘n’}
>>> c -= b
>>> c
{5, ‘l’, ‘n’}
>>> b
{‘j’, ‘r’, ‘m’, ‘o’, ‘a’}
>>> c.isdisjoint(b)
True
>>> a.isdisjoint(b)
False
[/xterm] - issubset(set) – retorna verdadeiro se o conjunto for um subconjunto do outro.
[xterm color=’true’ py=’true’]
>>> c
{5, ‘l’, ‘n’}
>>> a
{5, ‘l’, ‘j’, ‘r’, ‘a’, ‘n’}
>>> c.issubset(a)
True
>>> a.issubset(c)
False
[/xterm] - issuperset(set) – retorna verdadeiro se o conjunto argumento (set) for um subconjunto do conjunto. É o contrário do
issubset(set)
.[xterm color=’true’ py=’true’]
>>> c.issuperset(a)
False
>>> a.issuperset(c)
True
[/xterm]
[xterm color=’true’ py=’true’]
>>> c = a.copy()
>>> c.difference_update(b)
>>> c == a – b
True
>>> c = a.copy()
>>> c.intersection_update(b)
>>> c == a & b
True
>>> c = a.copy()
>>> c.update(b)
>>> c == a | b
True
>>> c = a.copy()
>>> c.symmetric_difference_update(b)
>>> c == a ^ b
True
[/xterm]
1.3. Set Comprehensions
Como em listas, conjuntos também podem ser gerados usando um set comprehensions, o qual funciona com uma expressão em um laço de repetição fechado entre chaves. As sintaxes suportadas são as mesmas de listas, apenas substituindo os colchetes por chaves:
{ for - in
}
{ for - in
if }
Seguem alguns exemplos:
[xterm color=’true’ py=’true’]
>>> a = {x for x in ‘abracadabra’ if x not in ‘abc’}
>>> b = {x for x in ‘abracadabra’ if x > ‘c’}
>>> a
{‘r’, ‘d’}
>>> a == b
True
[/xterm]
Duas formas diferentes de construir o mesmo conjunto das letras de ‘abracadabra’ maiores que c.
2. Considerações
A grande aplicação para conjuntos é o seu emprego como chaves em outras estruturas de dados como dicionários, apresentado próximo texto, ou chaves de bancos de dados, além de aplicações matemáticas como conjuntos. Embora não o tenha utilizado muito, é aconselhável ter consciência de suas possibilidades em momento de programação.
O próximo texto será sobre dicionários, uma estrutura de dados composta, mas que pode empregar qualquer tipo de imutável como índice, além de inteiros. A lista de índices de um dicionário, como veremos, é um conjunto.
Deixe uma resposta