Vai al contenuto
Leo

Parte I — Le basi

Capitolo 6 — Intervalli e fette

Chiudiamo la Parte I con un'idea piccola ma che ritorna continuamente: prendere un pezzo di una sequenza. In Leo si fa con gli intervalli, e la notazione è una delle più pulite che il linguaggio offra.

Gli intervalli

Un intervallo è un modo breve per dire «tutti i numeri da qui a lì». Si scrive con due punti .. tra gli estremi, che sono entrambi compresi:

Leo
per ogni i in 1..5 fai
    scrivi(i)
fine
Risultato
1
2
3
4
5

1..5 sono i numeri 1, 2, 3, 4, 5 — cinque numeri, estremi inclusi. Questa è una scelta deliberata di Leo: l'intervallo 1..5 contiene esattamente i numeri che un italiano direbbe «da uno a cinque», senza i trucchi del «fino a cinque escluso» di altri linguaggi. Gli intervalli funzionano anche all'indietro: 10..1 conta da dieci a uno.

Un intervallo non è solo per i cicli: puoi usarlo ovunque serva una sequenza di numeri, per esempio somma(1..100) o media(1..10).

🦁 Curiosità — Dove finisce una fetta

Leo include entrambi gli estremi, ma molti linguaggi diffusi fanno il contrario: la fetta parte dall'inizio indicato e si ferma appena prima del fondo. La ragione è elegante quanto la scelta di Leo: con gli intervalli «mezzi aperti» una fetta da 0 a 3 e una da 3 a 5 combaciano alla perfezione, senza sovrapporsi né lasciare buchi. Due filosofie diverse, ciascuna con la sua logica.

Le fette (slicing)

Lo stesso .., messo tra le parentesi quadre, prende una fetta di una lista o di un testo. Gli estremi sono — di nuovo — entrambi inclusi e contati da zero; un estremo negativo conta dalla fine:

Leo
variabile voti = [4, 6, 7, 9, 10]
scrivi(voti[0..2])
scrivi(voti[2..-1])
scrivi(voti[0..-1])
scrivi("Beatrice"[0..2])
scrivi("Beatrice"[2..-1])
Risultato
[4, 6, 7]
[7, 9, 10]
[4, 6, 7, 9, 10]
Bea
atrice

Leggiamole. voti[0..2] prende dall'elemento 0 all'elemento 2 compreso — i primi tre. voti[2..-1] va dall'elemento 2 fino all'ultimo (-1), cioè tutta la coda. voti[0..-1] è una scorciatoia utilissima: «dal primo all'ultimo», cioè tutta la sequenza. E poiché la stessa notazione vale per i testi, "Beatrice"[0..2] è "Bea" e "Beatrice"[2..-1] è "atrice".

Una fetta mantiene il tipo: una fetta di lista è una lista, una fetta di testo è un testo.

💡 L'idea — Come affettare il pane

Prendere una fetta di una lista o di un testo è come tagliare una fetta di pane: dici da dove a dove vuoi tagliare e ottieni esattamente quel pezzo, mentre il resto della pagnotta resta lì, intero, pronto per la prossima fetta. L'originale non si rovina: ne esce solo il pezzo che hai chiesto.

I bordi, senza drammi

Che succede se chiedi una fetta più grande della sequenza, o «al contrario»? Leo non va in errore: si comporta nel modo più ragionevole.

Leo
variabile voti = [4, 6, 7, 9, 10]
scrivi(voti[0..100])
scrivi(voti[3..1])
Risultato
[4, 6, 7, 9, 10]
[]

Se un estremo sfora, viene accostato al limite: voti[0..100] dà tutta la lista, senza lamentele. Se l'inizio viene dopo la fine (3..1), la fetta è semplicemente vuota, []. Questa tolleranza ti risparmia una quantità di controlli manuali.

Una fetta è una copia

C'è un dettaglio che vale oro quando i programmi crescono: prendere una fetta crea una lista nuova. Modificarla non tocca l'originale.

Leo
variabile voti = [4, 6, 7, 9, 10]
variabile copia = voti[0..-1]
copia.aggiungi(99)
scrivi(voti)
scrivi(copia)
Risultato
[4, 6, 7, 9, 10]
[4, 6, 7, 9, 10, 99]

voti[0..-1] ha prodotto una copia completa: aggiungendo 99 alla copia, l'originale è rimasto intatto. È il modo idiomatico, in Leo, per «fare una copia di una lista» prima di lavorarci sopra senza rischiare di rovinare i dati di partenza.

Per rovesciare una lista, invece, non usare una fetta: c'è il metodo apposito .inverti(), che hai visto nel capitolo scorso.

Prova tu

  1. Data la lista [10, 20, 30, 40, 50, 60], stampa separatamente la prima metà e la seconda metà usando due fette.
  2. Prendi una parola lunga e stampa le sue ultime tre lettere con una fetta che usa indici negativi.
  3. Fai una copia di una lista con [0..-1], ordina la copia e stampa entrambe per convincerti che l'originale non è cambiato.

Con questo si chiude la Parte I. Ora sai dichiarare dati, manipolarli e mostrarli. Nella Parte II daremo ai programmi la capacità di decidere e di ripetere: è lì che il codice comincia davvero a prendere vita.