List Comprehension

In questa lezione vedremo un nuovo fantastico e semplice metodo per creare liste e sotto-liste in Python, chiamato list comprehension (in italiano comprensione di lista).

Personalmente, sono un grande fan di questa tecnica, perché rende i nostri programmi estremamente più facili da leggere, e perché ci fa risparmiare davvero un sacco di tempo. Spiegherò le list comprehension nello stesso modo in cui le ho imparate io, facendo un confronto con la modalità diciamo "classica" di creazione di liste che abbiamo visto finora.

In Python una lista è formata da elementi provenienti da altre sequenze su cui sono state svolte determinate operazioni o da sotto-sequenze che rispettano determinate condizioni. Ad esempio, supponiamo di aver bisogno di una lista di quadrati a partire da un elenco di numeri, la prima cosa che probabilmente vi starà venendo in mente è:

  • Creiamo una lista vuota
  • Aggiungiamo a questa lista i quadrati dei numeri da elevare utilizzando un for loop
quadrati = []

for n in range(10):
    quadrati.append(n**2)

print(quadrati)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Tutto chiaro fin qui, giusto? Lasciate che vi mostri ora come possiamo ottenere lo stesso risultato, ma impiegando stavolta le list comprehension:

quadrati = [n**2 for n in range(10)]

print(quadrati)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Bella differenza no? Da una parte abbiamo usato tre righe di codice, mentre qui, semplicemente una. Inoltre è facile notare quanto la sintassi sia praticamente identica all'inglese parlato. Stiamo dicendo che vogliamo una lista di quadrati e che dentro ci vogliamo il quadrato di n per ciascun n dell'intervallo. Quindi, una list comprehension è creata utilizzando delle parentesi quadre contenenti al loro interno un'espressione, un ciclo for ed eventuali if se necessari.

Facciamo un altro esempio. Supponiamo ora di avere due liste di numeri:

lista_uno = [1, 2, 3]
lista_due = [3, 1, 4]

Abbiamo bisogno di combinare i valori presenti in queste due liste, purché questi siano diversi tra loro. Possiamo utilizzare un annidamento di cicli for, in questa maniera:

mix = []

for x in lista_uno:
    for y in lista_due:
        if x != y:
            mix.append((x, y))
            
print(mix)
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

Oppure, molto più semplicemente, rivolgerci alle list comprehension e svolgere il tutto con una singola riga di codice:

mix = [(x, y) for x in lista_uno for y in lista_due if x != y]

print(mix)
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

Allo stesso modo possiamo anche richiamare un metodo su ciascuno dei valori con cui vogliamo comporre la lista, oppure passarlo a una funzione. Ad esempio, supponiamo di aver bisogno di una lista contenente la versione stringata dei numeri contenuti in lista_uno. Con una list comprehension ci basta fare:

stringati = [str(n) for n in lista_uno]
print(stringati)
['1', '2', '3']

Mentre utilizzando un ciclo for avremmo dovuto fare:

stringati = []
for n in lista_uno:
    stringati.append(str(n))

print(stringati)
['1', '2', '3']