Co

Conjuntos em Python

16 exercícios

Sobre Conjuntos

Um set é uma coleção mutável e não ordenada de objetos hashable. Os elementos de um conjunto têm de ser distintos: não são permitidos itens duplicados. Podem conter vários tipos de dados diferentes e até estruturas aninhadas, como um tuple de tuples, desde que seja possível calcular o hash de todos os elementos. Os conjuntos também existem numa versão imutável frozenset.

Os conjuntos são habitualmente usados para remover rapidamente duplicados de outras estruturas de dados ou agrupamentos de itens. Também são usados para comparações eficientes quando não é preciso manter uma ordem nem controlar duplicados.

Tal como outros tipos de coleções (dicionários, listas, tuplas), os sets suportam:

  • Iteração com for item in <set>,
  • Verificação de pertença com in e not in,
  • Cálculo do comprimento com len(), e
  • Cópias superficiais com copy().

Os sets não suportam:

  • Indexação de qualquer tipo
  • Ordenação por sorting ou inserção
  • Fatiamento
  • Concatenação com +

Verificar a pertença num set tem complexidade temporal constante (em média), ao contrário de verificar a pertença numa list ou numa string, em que a complexidade temporal cresce à medida que o comprimento dos dados aumenta. Métodos como <set>.union(), <set>.intersection() ou <set>.difference() também têm complexidade temporal constante (em média).

Construção de conjuntos

Embora os conjuntos possam ser criados de várias formas diferentes, os métodos de construção mais diretos são declarar um literal de conjunto, usar o construtor da classe set (set()) e usar uma compreensão de conjunto.

Literais de conjunto

Um set pode ser escrito diretamente como um literal de conjunto, com chavetas {} e vírgulas entre os elementos. Os duplicados são omitidos silenciosamente:

>>> one_element = {'➕'}
{'➕'}

>>> multiple_elements = {'➕', '🔻', '🔹', '🔆'}
{'➕', '🔻', '🔹', '🔆'}

>>> multiple_duplicates =  {'Hello!', 'Hello!', 'Hello!', 
                            '¡Hola!','Привіт!', 'こんにちは!', 
                            '¡Hola!','Привіт!', 'こんにちは!'}
{'こんにちは!', '¡Hola!', 'Hello!', 'Привіт!'}

Os literais de conjunto usam as mesmas chavetas que os literais de dict, o que significa que tens de usar set() para criar um set vazio.

O construtor de conjuntos

set() (o construtor da classe set) pode ser usado com qualquer iterable passado como argumento. Os elementos do iterable são percorridos um a um e adicionados ao set individualmente. A ordem dos elementos não é preservada e os duplicados são omitidos silenciosamente:

# To create an empty set, the constructor must be used.
>>> no_elements = set()
set()

# The tuple is unpacked & each element is added.  
# Duplicates are removed.
>>> elements_from_tuple = set(("Parrot", "Bird", 
                               334782, "Bird", "Parrot"))
{334782, 'Bird', 'Parrot'}

# The list is unpacked & each element is added.
# Duplicates are removed.
>>> elements_from_list = set([2, 3, 2, 3, 3, 3, 5, 
                              7, 11, 7, 11, 13, 13])
{2, 3, 5, 7, 11, 13}

Compreensões de conjunto

Tal como lists e dicts, os conjuntos podem ser criados por compreensão:

# First, a list with duplicates
>>> numbers = [1,2,3,4,5,6,6,5,4,8,9,9,9,2,3,12,18]

# This set comprehension squares the numbers divisible by 3
# Duplicates are removed.
>>> calculated = {item**2 for item in numbers if item % 3 == 0}
{9, 36, 81, 144, 324}

Armadilhas ao criar conjuntos

Devido ao seu comportamento de "desempacotamento", usar o construtor set com uma string pode ser surpreendente:

# String elements (Unicode code points) are 
# iterated through and added *individually*.
>>> elements_string = set("Timbuktu")
{'T', 'b', 'i', 'k', 'm', 't', 'u'}

# Unicode separators and positioning code points 
# are also added *individually*.
>>> multiple_code_points_string = set('अभ्यास')
{'अ', 'भ', 'य', 'स', 'ा', '्'}

Lembra-te: os conjuntos podem conter tipos de dados diferentes e tipos de dados aninhados, mas todos os elementos de um set têm de ser hashable:

# Attempting to use a list for a set member throws a TypeError
>>> lists_as_elements = {['🌈','💦'], 
                        ['☁️','⭐️','🌍'], 
                        ['⛵️', '🚲', '🚀']}

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'


# Standard sets are mutable, so they cannot be hashed.
>>> sets_as_elements = {{'🌈','💦'}, 
                        {'☁️','⭐️','🌍'}, 
                        {'⛵️', '🚲', '🚀'}}

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'

No entanto, é possível criar um set de sets através do tipo frozenset():

# Frozensets don't have a literal form.
>>> set_1 = frozenset({'🌈','💦'})
>>> set_2 = frozenset({'☁️','⭐️','🌍'})
>>> set_3 = frozenset({'⛵️', '🚲', '🚀'})

>>> frozen_sets_as_elements = {set_1, set_2, set_3}
>>> frozen_sets_as_elements
{frozenset({'⛵️', '🚀', '🚲'}),
 frozenset({'🌈', '💦'}),
 frozenset({'☁️', '⭐️', '🌍'})}

Adicionar e remover elementos de um conjunto

Os elementos podem ser adicionados ou removidos de um set com os métodos <set>.add(<item>) e <set>.remove(<item>). O método .remove(<item>) lança um KeyError se o item não estiver presente no set:

>>> creatures = {'crow', 'duck', 'fish', 'monkey', 'elephant'}
>>> creatures.add('beaver')
>>> creatures.remove('duck')
>>> creatures
{'beaver', 'crow', 'elephant', 'fish', 'monkey'}

# Trying to remove an item that is not present raises a KeyError
>>> creatures.remove('bear')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  KeyError: 'bear'

Estratégias adicionais para remover elementos de um conjunto

  • <set>.discard(<item>) remove um item do set, mas não lança um KeyError se o item não estiver presente.
  • <set>.clear() remove todos os itens do conjunto.
  • <set>.pop() remove e devolve um item arbitrário, e lança um KeyError se o set estiver vazio.

Operações com conjuntos

Os conjuntos têm métodos que imitam, de um modo geral, as operações matemáticas de conjuntos. A maioria (não todos) destes métodos tem um operador equivalente. Os métodos aceitam, em geral, qualquer iterable como argumento, ao passo que os operadores exigem que ambos os lados da operação sejam sets ou frozensets.

Testar pertença entre conjuntos

O método <set>.isdisjoint(<other_collection>) serve para testar se os elementos de um set se sobrepõem, de alguma forma, aos elementos de outro. O método aceita qualquer iterable ou set como argumento. Devolve True se os dois conjuntos não tiverem elementos em comum e False se houver elementos partilhados.

# Both mammals and additional_animals are lists.
>>> mammals = ['squirrel','dog','cat','cow', 'tiger', 'elephant']
>>> additional_animals = ['pangolin', 'panda', 'parrot', 
                          'lemur', 'tiger', 'pangolin']

# Animals is a dict.
>>> animals = {'chicken': 'white',
               'sparrow': 'grey',
               'eagle': 'brown and white',
               'albatross': 'grey and white',
               'crow': 'black',
               'elephant': 'grey', 
               'dog': 'rust',
               'cow': 'black and white',
               'tiger': 'orange and black',
               'cat': 'grey',
               'squirrel': 'black'}
               
# Birds is a set.
>>> birds = {'crow','sparrow','eagle','chicken', 'albatross'}

# Mammals and birds don't share any elements.
>>> birds.isdisjoint(mammals)
True

# There are also no shared elements between 
# additional_animals and birds.
>>> birds.isdisjoint(additional_animals)
True

# Animals and mammals have shared elements.
# **Note** The first object needs to be a set or converted to a set
# since .isdisjoint() is a set method.
>>> set(animals).isdisjoint(mammals)
False

Verificar subconjuntos e superconjuntos

<set>.issubset(<other_collection>) serve para verificar se todos os elementos de <set> também estão em <other_collection>. A forma com operador é <set> <= <other_set>:

# Set methods will take any iterable as an argument.
# All members of birds are also members of animals.
>>> birds.issubset(animals)
True

# All members of mammals also appear in animals.
# **Note** The first object needs to be a set or converted to a set
# since .issubset() is a set method.
>>> set(mammals).issubset(animals)
True

# Both objects need to be sets to use a set operator
>>> birds <= set(mammals)
False

# A set is always a loose subset of itself.
>>> set(additional_animals) <= set(additional_animals)
True

<set>.issuperset(<other_collection>) é o inverso de .issubset(). Serve para verificar se todos os elementos de <other_collection> também estão em <set>. A forma com operador é <set> >= <other_set>:

# All members of mammals also appear in animals.
# **Note** The first object needs to be a set or converted to a set
# since .issuperset() is a set method.
>>> set(animals).issuperset(mammals)
True

# All members of animals do not show up as members of birds.
>>> birds.issuperset(animals)
False

# Both objects need to be sets to use a set operator
>>> birds >= set(mammals)
False

# A set is always a loose superset of itself.
>>> set(animals) >= set(animals)
True

Subconjuntos e superconjuntos 'próprios'

<set> < <other_set> e <set> > <other_set> servem para testar subconjuntos próprios. Um set é um subconjunto próprio se (<set> <= <other_set>) E (<set> != <other_set>) no caso do operador <.

Um set é um superconjunto próprio se (<set> >= <other_set>) E (<set> != <other_set>) no caso do operador >. Estes operadores não têm um método equivalente:

>>> animal_names = {'albatross','cat','chicken','cow','crow','dog',
                   'eagle','elephant','sparrow','squirrel','tiger'}

>>> animals_also = {'albatross','cat','chicken','cow','crow','dog',
                   'eagle','elephant','sparrow','squirrel','tiger'}

>>> mammals = {'squirrel','dog','cat','cow', 'tiger', 'elephant'}
>>> birds   = {'crow','sparrow','eagle','chicken', 'albatross'}

>>> mammals < animal_names
True

>>> animal_names > birds
True

# A set is not a *proper subset* if set == other set.
>>> animals_also < animal_names
False

# A set is never a *proper subset* of itself
>>> animals_also < animals_also
False

Uniões de conjuntos

<set>.union(*<other iterables>) devolve um novo set com os elementos de <set> e de todos os <other iterables>. A forma com operador deste método é <set> | <other set 1> | <other set 2> | ... | <other set n>.

>>> perennials = {'Asparagus', 'Broccoli', 'Sweet Potato', 'Kale'}
>>> annuals = {'Corn', 'Zucchini', 'Sweet Peas', 'Summer Squash'}
>>> more_perennials = ['Radicchio', 'Rhubarb', 
                      'Spinach', 'Watercress']

# Methods will take any iterable as an argument.
>>> perennials.union(more_perennials)
{'Asparagus','Broccoli','Kale','Radicchio','Rhubarb',
'Spinach','Sweet Potato','Watercress'}

# Operators require sets.
>>> set(more_perennials) | perennials
{'Asparagus',
 'Broccoli',
 'Kale',
 'Radicchio',
 'Rhubarb',
 'Spinach',
 'Sweet Potato',
 'Watercress'}

Diferenças de conjuntos

<set>.difference(*<other iterables>) devolve um novo set com os elementos do <set> original que não estão em <others>. A versão com operador deste método é <set> - <other set 1> - <other set 2> - ... - <other set n>.

>>> berries_and_veggies = {'Asparagus', 
                          'Broccoli', 
                          'Watercress', 
                          'Goji Berries', 
                          'Goose Berries', 
                          'Ramps', 
                          'Walking Onions', 
                          'Blackberries', 
                          'Strawberries', 
                          'Rhubarb', 
                          'Kale', 
                          'Artichokes', 
                          'Currants'}

>>> veggies = ('Asparagus', 'Broccoli', 'Watercress', 'Ramps',
               'Walking Onions', 'Rhubarb', 'Kale', 'Artichokes')

# Methods will take any iterable as an argument.
>>> berries = berries_and_veggies.difference(veggies)
{'Blackberries','Currants','Goji Berries',
 'Goose Berries', 'Strawberries'}

# Operators require sets.
>>> berries_and_veggies - berries
{'Artichokes','Asparagus','Broccoli','Kale',
'Ramps','Rhubarb','Walking Onions','Watercress'}

Interseções de conjuntos

<set>.intersection(*<other iterables>) devolve um novo set com os elementos comuns ao set original e a todos os <others> (por outras palavras, o set onde tudo se interseta). A versão com operador deste método é <set> & <other set> & <other set 2> & ... & <other set n>

>>> perennials = {'Annatto','Asafetida','Asparagus','Azalea',
                 'Winter Savory', 'Broccoli','Curry Leaf','Fennel', 
                 'Kaffir Lime','Kale','Lavender','Mint','Oranges',
                 'Oregano', 'Tarragon', 'Wild Bergamot'}

>>> annuals = {'Corn', 'Zucchini', 'Sweet Peas', 'Marjoram', 
              'Summer Squash', 'Okra','Shallots', 'Basil', 
              'Cilantro', 'Cumin', 'Sunflower', 'Chervil', 
              'Summer Savory'}

>>> herbs = ['Annatto','Asafetida','Basil','Chervil','Cilantro',
            'Curry Leaf','Fennel','Kaffir Lime','Lavender',
            'Marjoram','Mint','Oregano','Summer Savory', 
            'Tarragon','Wild Bergamot','Wild Celery',
            'Winter Savory']


# Methods will take any iterable as an argument.
>>> perennial_herbs = perennials.intersection(herbs)
{'Annatto', 'Asafetida', 'Curry Leaf', 'Fennel', 'Kaffir Lime',
 'Lavender', 'Mint', 'Oregano', 'Wild Bergamot','Winter Savory'}

# Operators require both groups be sets.
>>> annuals & set(herbs)
 {'Basil', 'Chervil', 'Marjoram', 'Cilantro'}

Diferenças simétricas de conjuntos

<set>.symmetric_difference(<other iterable>) devolve um novo set com os elementos que estão em <set> OU em <other>, mas não em ambos. A versão com operador deste método é <set> ^ <other set>.

>>> plants_1 = {'🌲','🍈','🌵', '🥑','🌴', '🥭'}
>>> plants_2 = ('🌸','🌴', '🌺', '🌲', '🌻', '🌵')


# Methods will take any iterable as an argument.
>>> fruit_and_flowers = plants_1.symmetric_difference(plants_2)
>>> fruit_and_flowers
{'🌸', '🌺', '🍈', '🥑', '🥭','🌻' }


# Operators require both groups be sets.
>>> fruit_and_flowers ^ plants_1
{'🌲',  '🌸', '🌴', '🌵','🌺', '🌻'}

>>> fruit_and_flowers ^ set(plants_2)
{'🥭', '🌴', '🌵', '🍈', '🌲', '🥑'}
Note

Uma diferença simétrica de mais de dois conjuntos origina um set que inclui tanto os elementos únicos de cada set COMO os elementos partilhados entre mais de dois conjuntos da série (mais detalhes no artigo da Wikipédia sobre diferença simétrica).

Para obter apenas os itens únicos de cada set da série, é preciso agregar num passo separado as interseções entre todas as combinações de dois conjuntos, e removê-las:

>>> one = {'black pepper','breadcrumbs','celeriac','chickpea flour',
           'flour','lemon','parsley','salt','soy sauce',
           'sunflower oil','water'}

>>> two = {'black pepper','cornstarch','garlic','ginger',
           'lemon juice','lemon zest','salt','soy sauce','sugar',
           'tofu','vegetable oil','vegetable stock','water'}

>>> three = {'black pepper','garlic','lemon juice','mixed herbs',
             'nutritional yeast', 'olive oil','salt','silken tofu',
             'smoked tofu','soy sauce','spaghetti','turmeric'}

>>> four = {'barley malt','bell pepper','cashews','flour',
            'fresh basil','garlic','garlic powder', 'honey',
            'mushrooms','nutritional yeast','olive oil','oregano',
            'red onion', 'red pepper flakes','rosemary','salt',
            'sugar','tomatoes','water','yeast'}

>>> intersections = (one & two | one & three | one & four | 
                     two & three | two & four | three & four)
...
{'black pepper','flour','garlic','lemon juice','nutritional yeast', 
'olive oil','salt','soy sauce', 'sugar','water'}

# The ^ operation will include some of the items in intersections, 
# which means it is not a "clean" symmetric difference - there
# are overlapping members.
>>> (one ^ two ^ three ^ four) & intersections
{'black pepper', 'garlic', 'soy sauce', 'water'}

# Overlapping members need to be removed in a separate step
# when there are more than two sets that need symmetric difference.
>>> (one ^ two ^ three ^ four) - intersections
...
{'barley malt','bell pepper','breadcrumbs', 'cashews','celeriac',
  'chickpea flour','cornstarch','fresh basil', 'garlic powder',
  'ginger','honey','lemon','lemon zest','mixed herbs','mushrooms',
  'oregano','parsley','red onion','red pepper flakes','rosemary',
  'silken tofu','smoked tofu','spaghetti','sunflower oil', 'tofu', 
  'tomatoes','turmeric','vegetable oil','vegetable stock','yeast'}
Editar via GitHub A ligação abre numa nova janela ou separador

Aprende Conjuntos

A prática está bloqueada

Desbloqueia mais 4 exercícios para praticares Conjuntos