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 conjuntoaque não estão contidos no conjuntobe os elementos debque 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 - bretorna os elementos dea, removidos os elementos semelhantes emb, ou seja apenas os elementos ‘n’ e ‘l’. O contrário,b - aretornará 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
besta contido ema, as duas primeiras comparações (a > beb < 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,
crecebe uma cópia dea. Jádapenas aponta para o objeto dec. Ao apagarc,dtambé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