Un set è una collezione mutabile e non ordinata di oggetti hashable.
Gli elementi di un set devono essere distinti: gli elementi duplicati non sono ammessi.
Possono contenere più tipi di dati diversi e persino strutture annidate come una tuple di tuples, purché tutti gli elementi possano essere sottoposti a hash.
I set esistono anche in una variante immutabile, il frozenset.
I set si usano più comunemente per rimuovere rapidamente i duplicati da altre strutture dati o raggruppamenti di elementi. Si usano anche per confronti efficienti quando non servono l'ordinamento e il tracciamento dei duplicati.
Come gli altri tipi di collezione (dizionari, array, tuple), i sets supportano:
for item in <set>,in e not in,len(), ecopy().I sets non supportano:
+
La verifica di appartenenza in un set ha complessità temporale costante (in media), a differenza della verifica di appartenenza in un list o in una string, dove la complessità temporale cresce con l'aumentare della lunghezza dei dati.
Anche metodi come <set>.union(), <set>.intersection() o <set>.difference() hanno complessità temporale costante (in media).
Sebbene i set si possano creare in molti modi diversi, i metodi di costruzione più diretti sono dichiarare un letterale di set, usare il costruttore della classe set (set()) e usare una comprensione di set.
Un set può essere scritto direttamente come letterale di set con parentesi graffe {} e virgole tra gli elementi.
I duplicati vengono omessi silenziosamente:
>>> one_element = {'➕'}
{'➕'}
>>> multiple_elements = {'➕', '🔻', '🔹', '🔆'}
{'➕', '🔻', '🔹', '🔆'}
>>> multiple_duplicates = {'Hello!', 'Hello!', 'Hello!',
'¡Hola!','Привіт!', 'こんにちは!',
'¡Hola!','Привіт!', 'こんにちは!'}
{'こんにちは!', '¡Hola!', 'Hello!', 'Привіт!'}
I letterali di set usano le stesse parentesi graffe dei letterali dict, il che significa che per creare un set vuoto devi usare set().
set() (il costruttore della classe set) può essere usato con qualsiasi iterable passato come argomento.
Gli elementi dell'iterable vengono percorsi uno alla volta e aggiunti al set singolarmente.
L'ordine degli elementi non viene preservato e i duplicati vengono omessi silenziosamente:
# 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}
Come le lists e le dicts, i set si possono creare tramite comprensione:
# 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}
A causa del suo comportamento di «unpacking», usare il costruttore set con una stringa potrebbe sorprendere:
# 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('अभ्यास')
{'अ', 'भ', 'य', 'स', 'ा', '्'}
Ricorda: i set possono contenere tipi di dati diversi e tipi di dati annidati, ma tutti gli elementi di un set devono essere 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'
Tuttavia, si può creare un set di set tramite il 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({'☁️', '⭐️', '🌍'})}
Gli elementi si possono aggiungere o rimuovere da un set usando i metodi <set>.add(<item>) e <set>.remove(<item>).
Il metodo .remove(<item>) solleva un KeyError se l'elemento non è presente nel 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'
<set>.discard(<item>) rimuove un elemento dal set, ma non solleva un KeyError se l'elemento non è presente.<set>.clear() rimuove tutti gli elementi dal set.<set>.pop() rimuove e restituisce un elemento arbitrario e solleva un KeyError se il set è vuoto.I set hanno metodi che in genere imitano le operazioni insiemistiche matematiche.
La maggior parte (non tutti) di questi metodi ha un equivalente come operatore.
I metodi in genere accettano qualsiasi iterable come argomento, mentre gli operatori richiedono che entrambi i lati dell'operazione siano set o frozenset.
Il metodo <set>.isdisjoint(<other_collection>) serve a verificare se gli elementi di un set si sovrappongono in qualche modo a quelli di un altro.
Il metodo accetta qualsiasi iterable o set come argomento.
Restituisce True se i due set non hanno elementi in comune, False se ci sono elementi condivisi.
# 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
<set>.issubset(<other_collection>) serve a verificare se ogni elemento di <set> è presente anche in <other_collection>.
La forma con operatore è <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>) è l'inverso di .issubset().
Serve a verificare se ogni elemento di <other_collection> è presente anche in <set>.
La forma con operatore è <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
<set> < <other_set> e <set> > <other_set> servono a verificare i sottoinsiemi propri.
Un set è un sottoinsieme proprio se, per l'operatore <, vale (<set> <= <other_set>) E (<set> != <other_set>).
Un set è un sovrainsieme proprio se, per l'operatore >, vale (<set> >= <other_set>) E (<set> != <other_set>).
Questi operatori non hanno un metodo 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
<set>.union(*<other iterables>) restituisce un nuovo set con gli elementi di <set> e di tutti gli <other iterables>.
La forma con operatore di questo metodo è <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'}
<set>.difference(*<other iterables>) restituisce un nuovo set con gli elementi del <set> originale che non sono presenti in <others>.
La versione con operatore di questo metodo è <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'}
<set>.intersection(*<other iterables>) restituisce un nuovo set con gli elementi comuni al set originale e a tutti gli <others> (in altre parole, il set in cui tutto si interseca).
La versione con operatore di questo metodo è <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'}
<set>.symmetric_difference(<other iterable>) restituisce un nuovo set che contiene gli elementi presenti in <set> O in <other>, ma non in entrambi.
La versione con operatore di questo metodo è <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)
{'🥭', '🌴', '🌵', '🍈', '🌲', '🥑'}
Una differenza simmetrica di più di due set produce un set che include sia gli elementi unici di ciascun set sia gli elementi condivisi tra più di due set della serie (dettagli nell'articolo di Wikipedia sulla differenza simmetrica).
Per ottenere solo gli elementi unici di ciascun sets della serie, occorre aggregare in un passaggio separato le intersezioni tra tutte le combinazioni di 2 set e rimuoverle:
>>> 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'}