Un insieme è una collezione mutabile e non ordinata di oggetti hashable.
Gli elementi di un insieme devono essere distinti: non sono ammessi duplicati.
Possono contenere più tipi di dati diversi e persino strutture annidate come una tuple di tuples, purché tutti gli elementi siano hashable.
Gli insiemi esistono anche in una versione immutabile: i frozensets.
Gli insiemi sono usati più comunemente per rimuovere rapidamente i duplicati da altre strutture dati o raggruppamenti di elementi. Si usano anche per confronti efficienti quando non serve mantenere una sequenza né tenere traccia dei duplicati.
Come altri tipi di collezione (dizionari, liste, tuple), i sets supportano:
for item in <set>
in e not in,len(), ecopy()
I sets non supportano:
+
Verificare l'appartenenza a un set ha complessità temporale costante (in media), mentre verificare l'appartenenza a una list o a una string ha una complessità che cresce all'aumentare della lunghezza dei dati.
Anche metodi come <set>.union(), <set>.intersection() o <set>.difference() hanno complessità temporale costante (in media).
Un set può essere scritto direttamente come letterale di insieme, 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 insieme 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 e aggiunti al set uno per uno.
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}
A causa del suo comportamento di «unpacking», usare set() con una stringa può 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('अभ्यास')
{'अ', 'भ', 'य', 'स', 'ा', '्'}
Gli insiemi 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'
Gli insiemi hanno metodi che in genere imitano le operazioni matematiche sugli insiemi.
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 sets o frozensets.
Il metodo <set>.isdisjoint(<other_collection>) serve a verificare se gli elementi di un set si sovrappongono in qualche modo agli elementi di un altro set.
Il metodo accetta qualsiasi iterable o set come argomento.
Restituisce True se i due insiemi non hanno elementi in comune, False se ci sono elementi condivisi.
Non esiste un operatore equivalente:
# 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>:
# 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'}
# 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>.intersection(*<other iterables>) restituisce un nuovo set con gli elementi in comune tra il set originale e 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>.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>.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)
{'🥭', '🌴', '🌵', '🍈', '🌲', '🥑'}
La differenza simmetrica di più di due insiemi produce un set che include sia gli elementi unici di ciascun set SIA gli elementi condivisi tra più di due insiemi della serie (dettagli nell'articolo di Wikipedia sulla differenza simmetrica).
Per ottenere solo gli elementi unici di ciascun sets della serie, le intersezioni tra tutte le combinazioni di 2 insiemi devono essere aggregate in un passaggio separato e poi rimosse:
>>> 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'}
Tu e i tuoi partner commerciali gestite una piccola azienda di catering. Avete appena accettato di organizzare un evento per un club di cucina locale, con protagonista i piatti «preferiti dal club». Il club ha poca esperienza nell'organizzare grandi eventi e ha bisogno di aiuto per l'organizzazione, la spesa, la preparazione e il servizio. Hai deciso di scrivere alcuni piccoli script Python per velocizzare l'intero processo di pianificazione.
Le ricette dell'evento sono state aggiunte da fonti diverse e i loro ingredienti sembrano avere voci duplicate (o anche di più): non vuoi ritrovarti a comprare quantità eccessive! Prima di poter iniziare la spesa e la cucina, la lista degli ingredienti di ogni piatto deve essere «ripulita».
Implementa la funzione clean_ingredients(<dish_name>, <dish_ingredients>), che prende il nome di un piatto e una list di ingredienti.
Questa funzione dovrebbe restituire una tuple con il nome del piatto come primo elemento, seguita dal set di ingredienti senza duplicati.
>>> clean_ingredients('Punjabi-Style Chole', ['onions', 'tomatoes', 'ginger paste', 'garlic paste', 'ginger paste', 'vegetable oil', 'bay leaves', 'cloves', 'cardamom', 'cilantro', 'peppercorns', 'cumin powder', 'chickpeas', 'coriander powder', 'red chili powder', 'ground turmeric', 'garam masala', 'chickpeas', 'ginger', 'cilantro'])
>>> ('Punjabi-Style Chole', {'garam masala', 'bay leaves', 'ground turmeric', 'ginger', 'garlic paste', 'peppercorns', 'ginger paste', 'red chili powder', 'cardamom', 'chickpeas', 'cumin powder', 'vegetable oil', 'tomatoes', 'coriander powder', 'onions', 'cilantro', 'cloves'})
All'evento ci saranno sia cocktail sia «mocktail»: bevande miscelate senza alcol. Devi assicurarti che le bevande «mocktail» siano davvero analcoliche e che i cocktail contengano davvero alcol.
Implementa la funzione check_drinks(<drink_name>, <drink_ingredients>), che prende il nome di una bevanda e una list di ingredienti.
La funzione dovrebbe restituire il nome della bevanda seguito da "Mocktail" se la bevanda non ha ingredienti alcolici, e il nome della bevanda seguito da "Cocktail" se la bevanda contiene alcol.
Ai fini di questo esercizio, i cocktail includeranno solo alcolici provenienti dalla costante ALCOHOLS in sets_categories_data.py:
>>> from sets_categories_data import ALCOHOLS
>>> check_drinks('Honeydew Cucumber', ['honeydew', 'coconut water', 'mint leaves', 'lime juice', 'salt', 'english cucumber'])
...
'Honeydew Cucumber Mocktail'
>>> check_drinks('Shirley Tonic', ['cinnamon stick', 'scotch', 'whole cloves', 'ginger', 'pomegranate juice', 'sugar', 'club soda'])
...
'Shirley Tonic Cocktail'
La lista degli invitati include commensali con esigenze alimentari diverse, e il tuo staff dovrà suddividere i piatti in Vegan, Vegetarian, Paleo, Keto e Omnivore. Un piatto appartiene a una categoria solo se tutti i suoi ingredienti compaiono nell'insieme di ingredienti della categoria.
Implementa la funzione categorize_dish(<dish_name>, <dish_ingredients>), che prende il nome di un piatto e un set degli ingredienti di quel piatto.
La funzione dovrebbe restituire una stringa con dish name: <CATEGORY> (a quale categoria di portata appartiene il piatto).
Tutti i piatti forniti rientreranno in una delle categorie importate da sets_categories_data.py (VEGAN, VEGETARIAN, PALEO, KETO o OMNIVORE).
>>> from sets_categories_data import VEGAN, VEGETARIAN, PALEO, KETO, OMNIVORE
>>> categorize_dish('Sticky Lemon Tofu', {'tofu', 'soy sauce', 'salt', 'black pepper', 'cornstarch', 'vegetable oil', 'garlic', 'ginger', 'water', 'vegetable stock', 'lemon juice', 'lemon zest', 'sugar'})
...
'Sticky Lemon Tofu: VEGAN'
>>> categorize_dish('Shrimp Bacon and Crispy Chickpea Tacos with Salsa de Guacamole', {'shrimp', 'bacon', 'avocado', 'chickpeas', 'fresh tortillas', 'sea salt', 'guajillo chile', 'slivered almonds', 'olive oil', 'butter', 'black pepper', 'garlic', 'onion'})
...
'Shrimp Bacon and Crispy Chickpea Tacos with Salsa de Guacamole: OMNIVORE'
Alcuni invitati hanno allergie e ulteriori restrizioni alimentari. Questi ingredienti devono essere contrassegnati/annotati per ogni piatto, in modo che non causino problemi.
Implementa la funzione tag_special_ingredients(<dish>), che prende una tuple con il nome del piatto in prima posizione e una list o un set di ingredienti per quel piatto in seconda posizione.
Restituisci il nome del piatto seguito dal set di ingredienti che richiedono una nota speciale nella descrizione del piatto.
Gli ingredienti di un piatto all'interno di una list possono avere o non avere duplicati.
Ai fini di questo esercizio, tutti gli allergeni o gli ingredienti speciali da etichettare si trovano nella costante SPECIAL_INGREDIENTS importata da sets_categories_data.py.
>>> from sets_categories_data import SPECIAL_INGREDIENTS
>>> tag_special_ingredients(('Ginger Glazed Tofu Cutlets', ['tofu', 'soy sauce', 'ginger', 'corn starch', 'garlic', 'brown sugar', 'sesame seeds', 'lemon juice']))
...
('Ginger Glazed Tofu Cutlets', {'garlic','soy sauce','tofu'})
>>> tag_special_ingredients(('Arugula and Roasted Pork Salad', ['pork tenderloin', 'arugula', 'pears', 'blue cheese', 'pine nuts', 'balsamic vinegar', 'onions', 'black pepper']))
...
('Arugula and Roasted Pork Salad', {'pork tenderloin', 'blue cheese', 'pine nuts', 'onions'})
In preparazione dell'ordine e della spesa, dovrai compilare una «lista principale» di ingredienti per tutto ciò che è nel menù (le quantità verranno inserite in seguito).
Implementa la funzione compile_ingredients(<dishes>), che prende una list di piatti e restituisce un set di tutti gli ingredienti presenti in tutti i piatti elencati.
Ogni singolo piatto è rappresentato dal suo set di ingredienti.
dishes = [ {'tofu', 'soy sauce', 'ginger', 'corn starch', 'garlic', 'brown sugar', 'sesame seeds', 'lemon juice'},
{'pork tenderloin', 'arugula', 'pears', 'blue cheese', 'pine nuts',
'balsamic vinegar', 'onions', 'black pepper'},
{'honeydew', 'coconut water', 'mint leaves', 'lime juice', 'salt', 'english cucumber'}]
>>> compile_ingredients(dishes)
...
{'arugula', 'brown sugar', 'honeydew', 'coconut water', 'english cucumber', 'balsamic vinegar', 'mint leaves', 'pears', 'pork tenderloin', 'ginger', 'blue cheese', 'soy sauce', 'sesame seeds', 'black pepper', 'garlic', 'lime juice', 'corn starch', 'pine nuts', 'lemon juice', 'onions', 'salt', 'tofu'}
Gli organizzatori ti hanno dato una lista di piatti che vorrebbero preparare come antipasti «da un boccone», da servire su vassoi. Devi estrarli dalla lista principale dei piatti preparati come porzioni più grandi.
Implementa la funzione separate_appetizers(<dishes>, <appetizers>), che prende una list di nomi di piatti e una list di nomi di antipasti.
La funzione dovrebbe restituire la list dei nomi dei piatti con i nomi degli antipasti rimossi.
Sia la list <dishes> sia la list <appetizers> potrebbe contenere duplicati e potrebbe richiedere la rimozione dei duplicati.
dishes = ['Avocado Deviled Eggs','Flank Steak with Chimichurri and Asparagus', 'Kingfish Lettuce Cups',
'Grilled Flank Steak with Caesar Salad','Vegetarian Khoresh Bademjan','Avocado Deviled Eggs',
'Barley Risotto','Kingfish Lettuce Cups']
appetizers = ['Kingfish Lettuce Cups','Avocado Deviled Eggs','Satay Steak Skewers',
'Dahi Puri with Black Chickpeas','Avocado Deviled Eggs','Asparagus Puffs',
'Asparagus Puffs']
>>> separate_appetizers(dishes, appetizers)
...
['Vegetarian Khoresh Bademjan', 'Barley Risotto', 'Flank Steak with Chimichurri and Asparagus',
'Grilled Flank Steak with Caesar Salad']
All'interno di ogni categoria (Vegan, Vegetarian, Paleo, Keto, Omnivore), estrarrai gli ingredienti che compaiono in un solo piatto. A questi ingredienti «singleton» verrà assegnato un incaricato speciale per la spesa, così da non dimenticarli nella fretta di completare tutto il resto.
Implementa la funzione singleton_ingredients(<dishes>, <INTERSECTIONS>), che prende una list di piatti e una costante <CATEGORY>_INTERSECTIONS per la stessa categoria.
Ogni piatto è rappresentato da un set dei suoi ingredienti.
Ogni <CATEGORY>_INTERSECTIONS è un set di ingredienti che compaiono in più di un piatto della categoria.
Usando le operazioni sugli insiemi, la tua funzione dovrebbe restituire un set di ingredienti «singleton» (ingredienti che compaiono in un solo piatto della categoria).
from sets_categories_data import example_dishes, EXAMPLE_INTERSECTION
>>> singleton_ingredients(example_dishes, EXAMPLE_INTERSECTION)
...
{'garlic powder', 'sunflower oil', 'mixed herbs', 'cornstarch', 'celeriac', 'honey', 'mushrooms', 'bell pepper', 'rosemary', 'parsley', 'lemon', 'yeast', 'vegetable oil', 'vegetable stock', 'silken tofu', 'tofu', 'cashews', 'lemon zest', 'smoked tofu', 'spaghetti', 'ginger', 'breadcrumbs', 'tomatoes', 'barley malt', 'red pepper flakes', 'oregano', 'red onion', 'fresh basil'}
Iscriviti a Exercism per imparare e padroneggiare Python con 17 concetti146 esercizi e il mentoring di persone reali, tutto gratis.