# Lezione 12 - Il ciclo for

# ---==== IL CICLO FOR ====---

# Sintassi:
# for elemento in lista:
#    # Blocco di istruzioni

# Il for è un ciclo come il while, ma è più adatto per scorrere gli elementi di una lista.
# La differenza sostanziale tra i due cicli è che il ciclo for è più semplice da utilizzare
# quando si deve scorrere una sequenza di elementi, come ad esempio una lista. Ma, soprattutto,
# il ciclo for non utilizza una condizione booleana per determinare il numero di iterazioni,
# bensì scorre tutti gli elementi della lista.

# Per essere precisi, il ciclo for scorre tutti gli elementi di un oggetto iterabile, non
# necessariamente una lista. Un oggetto iterabile è un oggetto su cui è possibile iterare,
# cioè scorrere tutti gli elementi. Ad esempio, oltre alle liste, anche le stringhe sono
# oggetti iterabili.

# Esempio:
lista = [10, 20, 30, 40, 50]
for elemento in lista:
    print(elemento)

# Output:
# 10
# 20
# 30
# 40
# 50

# Il ciclo for scorre tutti gli elementi della lista e per ognuno di essi esegue il blocco di istruzioni.
# Per fare la stessa cosa con il ciclo while, bisognerebbe utilizzare un contatore e accedere agli elementi
# della lista tramite l'indice.

contatore = 0
while contatore < len(lista):
    print(lista[contatore])
    contatore += 1

# Output: uguale a quello del ciclo for

# Il ciclo for può essere utilizzato anche con le stringhe.
# Esempio:
stringa = "ciao"
for carattere in stringa:
    print(carattere)

# Output:
# c
# i
# a
# o

# Il ciclo for può essere utilizzato anche con lo slicing.
# Esempio:
lista = [10, 20, 30, 40, 50]
for elemento in lista[1:4]:
    print(elemento)

# Output:
# 20
# 30
# 40

# Immagino si veda immediatamente la comodità del ciclo for rispetto al while in questo caso, ma
# anche in molti altri casi. Infatti, d'ora in poi vi capiterà spesso di utilizzare il ciclo for
# al posto del while, soprattutto quando si tratta di scorrere una lista o una stringa.
# A questo punto il ciclo while diventa migliore del for solo quando si deve eseguire un blocco
# sulla base di una condizione booleana oppure quando si deve usare un while True.

# Funzione built-in range():
# La funzione range() permette di generare una SEQUENZA di numeri interi.
# La sintassi è la seguente:
# range(start, stop, step)
# - start: numero di partenza (incluso)
# - stop: numero di fine (escluso)
# - step: passo
# Quindi la sintassi è simile a quella dello slicing.

# Esempio:
numeri = range(1, 6)
print(numeri)  # Output: range(1, 6)

# La funzione range() restituisce un oggetto range, che è un oggetto iterabile. Non è una lista,
# ma può essere utilizzato in un ciclo for come se fosse una lista.
# La differenza principale tra un oggetto range e una lista è che un oggetto range non occupa spazio
# in memoria per memorizzare tutti i numeri della sequenza, ma li genera al momento del bisogno. Tutto qui.

# Esempio:
for numero in range(1, 4):
    print(numero)

# Output:
# 1
# 2
# 3

# Equivalente a:
for numero in [1, 2, 3]:
    print(numero)

# Equivalente a:
contatore = 1
while contatore < 4:
    print(contatore)
    contatore += 1

# Quando è soltanto necessario iterare un numero fisso di volte, la variabile di iterazione
# del ciclo for può essere sostituita con un underscore (_).
# Esempio:
for _ in range(3):
    print("ciao")
