15. Tuple e Set

In questa lezione parleremo di due nuovi tipi di dato: tuple e set.


Le tuple in Python

Come il tipo di dato lista visto nelle lezioni precedenti, anche il tipo tuple di Python rappresenta un insieme di elementi, definiti stavolta utilizzando una coppia di parentesi tonde, oppure senza alcuna parentesi ma separati da virgola.

>>> tupla = (2, 4, 9, 15, 23)
>>> type(tupla)

# output
<class 'tuple'>

###################

>>> tupla

# output
(2, 4, 9, 15, 23)

###################

>>> tupla_due = 7, 8, 9
>>> tupla_due

# output
(7, 8, 9)

Come per le liste, possiamo accedere agli elementi delle tuple utilizzando l'indice.

>>> tupla = (2, 4, 9, 15, 23)
>>> tupla[0]

# output
2

Le tuple sono immutabili

La grande differenza tra i tipi di dato tuple e list è che le tuple sono immutabili. Per questo motivo il dato tuple non dispone di un metodo append() e non possiamo usare l'istruzione del per rimuovere elementi. Questo risulta molto comodo in certe situazioni: tenetelo a mente!

>>> tupla.append(999)

# output
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'append'

#####################################

>>> del tupla[0]

# output
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object doesn't support item deletion


I set di Python

I set sono un altro tipo di dato di Python che permette di creare collezioni di elementi. I set vengono definiti con una coppia di parentesi graffe, e i valori sono separati da virgola

>>> my_set = {"asd", "qwerty", "cmd"}
>>> type(my_set)

# output
<class 'set'>

La caratteristica fondamentale dei set è che non possono contenere duplicati al loro interno.

>>> new_set = {"asd", "asd", "qwerty", "cmd"}
>>> new_set

# output
{'qwerty', 'cmd', 'asd'}

Il metodo add() dei set

A differenza delle tuple possiamo però aggiungere nuovi elementi col metodo add.

Provare ad aggiungere elementi già presenti non funzionerà!

>>> new_set = {"asd", "asd", "qwerty", "cmd"}
>>> new_set.add("cmd")
>>> new_set

# output
{'qwerty', 'cmd', 'asd'}

##############################

>>> new_set.add("nova")
>>> new_set

# output
{'qwerty', 'cmd', 'asd', 'nova'}


Approfondimento: Gli iterabili in Python

Finora abbiamo visto diversi tipi di dato in Python, come i numeri interi, i valori booleani, le liste e le stringhe.

C’è però una caratteristica che accomuna alcuni di questi tipi di dato: le stringhe, le liste, le tuple, i set e i dizionari (che vedremo in una lezione successiva), sono tutti oggetti che possono essere trattati come sequenze che contengono elementi accessibili per essere manipolati. Questo tipo di oggetti in Python sono detti iterabili. Gli altri tipi di dato, come ad esempio i booleani e i numeri int o float non sono iterabili perché rappresentano un unico valore o una singola entità e non contengono elementi.


Funzioni per iterabili

Python fornisce diverse funzioni per manipolare gli elementi degli iterabili, vediamo alcune delle più utilizzate:

La funzione max()

La funzione max() viene utilizzata per trovare il valore massimo di un oggetto iterabile.

max(iterable, key=None, default=None)

Dove iterable è la sequenza di cui si vuole trovare il valore massimo. Ad esempio possiamo usare max() per ottenere il numero maggiore in un set di numeri:

numeri = {3, 8, 1, 6, 9, 4}
valore_massimo = max(numeri)
print(valore_massimo) 

# output
9

L'argomento default specifica il valore da restituire se l'insieme di input è vuoto, mentre l’argomento key specifica un criterio di ordinamento personalizzato, ad esempio se gli passiamo len possiamo ottenere la parola più lunga in una tupla di parole:

parole = ('casa', 'auto', 'giardino', 'mestolo')
parola_più_lunga = max(parole, key=len)
print(parola_più_lunga) 

# output
giardino

La funzione sum()

La funzione sum() restituisce la somma degli elementi di un oggetto iterabile:

sum(iterable, start=0)

Dove iterable è l'oggetto iterabile che si desidera sommare e start è il valore di partenza opzionale della somma che per impostazione predefinita è uguale a zero, quindi se non viene specificato viene sommato il valore di tutti gli elementi. Ad esempio, sommiamo con sum() tutti gli elementi da una lista di numeri:

numeri = [33, 78, 5, 42, 23]
totale = sum(numeri)

print(totale)

# output
181

Vediamo cosa succede se impostiamo a 100 il valore di partenza:

totale = sum(numeri, 100)
print(totale)

# output
281

La funzione enumerate()

La funzione enumerate() consente di iterare su una sequenza (liste, tuple, stringhe, ecc.) e restituire una tupla contenente il valore dell'elemento corrente e il suo indice:

enumerate(sequence, start=0)

Dove sequence è la sequenza da iterare e start è l'indice di partenza per la numerazione (il valore predefinito è 0). Ad esempio, se vogliamo stampare il nome di ogni frutto di una lista insieme al suo indice, possiamo utilizzare la funzione enumerate() in questo modo:

frutta = ["mela", "banana", "kiwi", "arancia"]
for indice, frutto in enumerate(frutta):
    print(indice, frutto)

# output
0 mela
1 banana
2 kiwi
3 arancia

In questo caso enumerate() restituisce una sequenza di tuple contenenti l'indice e il valore corrente della lista frutta. Queste tuple vengono assegnate alle variabili indice e frutto e vengono utilizzate all'interno del ciclo for per stampare il nome del frutto insieme al suo indice.

Se non c’è bisogno di utilizzare l'indice si può utilizzare l'underscore _ al posto della variabile indice:

frutta = ["mela", "banana", "kiwi", "arancia"]
for _, frutto in enumerate(frutta):
    print(frutto)

# output
mela
banana
kiwi
arancia

La funzione sorted()

La funzione sorted() viene utilizzata per ordinare un iterabile. A differenza del metodo per liste sort(), che ha lo stesso scopo, può essere usato anche per le tuple e i set perché non modifica l'ordine degli elementi all'interno della sequenza originale ma la lascia invariata restituendo una nuova lista.

sorted(iterable, key=None, reverse=False)

Dove iterable è la sequenza di cui si vuole ordinare gli elementi. Come abbiamo visto per max(), anche in questo caso key consente di specificare un criterio di ordinamento personalizzato, mentre l'argomento reverse, se impostato su True, fa in modo che gli elementi siano in ordine decrescente.

Vediamo un esempio di utilizzo di sorted() a partire da una tupla:

numeri = (3, 8, 1, 6, 9, 4)
numeri_ordinati = sorted(numeri)
print(numeri_ordinati)

# output
[1, 3, 4, 6, 8, 9]

La funzione filter()

La funzione filter() prende in input una funzione e un iterabile e restituisce un nuovo iterabile contenente solo gli elementi dell'input per i quali la funzione restituisce True.

filter(funzione, iterabile)

Vediamo un esempio in cui controlliamo se un numero è pari o non lo è:

def numero_pari(n):
    return n % 2 == 0

numeri = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numeri_pari = list(filter(numero_pari, numeri))

print(numeri_pari)

# output
[2, 4, 6, 8, 10]

La funzione filter() viene utilizzata per filtrare solo i numeri pari dall'elenco di numeri.

La funzione map()

La funzione map() permette di applicare una stessa funzione ad ogni elemento di un oggetto iterabile e restituisce un nuovo oggetto iterabile dello stesso tipo di quello di partenza contenente i risultati della funzione applicata a ciascun elemento.

map(function, iterable, ...)

È necessario specificare nell'argomento function la funzione che si desidera applicare a ciascun elemento dell’argomento iterable. Come indicano i puntini, la funzione può anche essere applicata a più oggetti iterabili contemporaneamente, basta passarli come argomento, e può essere utilizzata con qualsiasi funzione, anche definite dall'utente. Ad esempio, applichiamo a una lista di numeri una funzione che li triplica:

numeri = [1, 2, 3, 4, 5]

def triplica(n):
    return n * 3

numeri_triplicati = list(map(triplica, numeri))
print(numeri_triplicati)

# output
[3, 6, 9, 12, 15]