Track
/
Swift
Swift
/
Esercizi
/
Esperto mixologo
Esperto mixologo

Esperto mixologo

Esercizio di apprendimento

Introduzione

Switch

Un'istruzione switch ti permette di confrontare un valore con diversi possibili valori corrispondenti. Ti consente di scrivere codice più conciso rispetto all'uso di più istruzioni else-if. Un'istruzione switch inizia con la parola chiave switch, seguita dal valore da confrontare. Poi puoi definire i casi usando la parola chiave case, seguita dal valore con cui confrontare. La parola chiave default serve a definire il caso predefinito quando nessuno dei casi corrisponde. Come le istruzioni else-if, le istruzioni switch eseguono solo il blocco di codice associato al primo caso che corrisponde.

switch value {
case 1:
    print("One")
case 2:
    print("Two")
default:
    print("Other")
}

Considera il seguente esempio:

if str == "apple" {
    print("Let's bake an apple crumble")
} else if str == "lemon" {
    print("Let's bake a lemon meringue pie!")
} else if str == "peach" {
    print("Let's bake a peach pie!")
} else {
    print("Let's buy ice cream.")
}

In alternativa, si potrebbe scrivere così:

switch str {
case "apple":
    print("Let's bake an apple crumble")
case "lemon":
    print("Let's bake a lemon meringue pie!")
case "peach":
    print("Let's bake a peach pie!")
default:
    print("Let's buy ice cream.")
}

Cicli while

Un ciclo while è un'istruzione di controllo del flusso che permette di eseguire del codice finché una certa condizione è vera. Swift fornisce due tipi di cicli while: i cicli while e i cicli repeat-while. La condizione di un ciclo while viene valutata prima che il corpo del ciclo venga eseguito; se la condizione è falsa, il corpo del ciclo non verrà eseguito affatto. I cicli while in Swift hanno la seguente struttura:

while <#condition#> {
  <#code#>
}

Qui il ciclo verrà eseguito finché count è maggiore di 0, e stamperà quindi i numeri 2, 1 e «Liftoff!».

var count = 2
while count > 0 {
  print("\(count)…")
  count -= 1
}
print("Liftoff!")

// prints:
// 2…
// 1…
// Liftoff!

Un ciclo repeat-while è simile a un ciclo while, ma la condizione viene valutata dopo che il corpo del ciclo è stato eseguito. Questo significa che il corpo del ciclo verrà eseguito sempre almeno una volta, anche se la condizione è falsa. I cicli repeat-while in Swift hanno la seguente struttura:

repeat {
  <#code#>
} while <#condition#>

Qui il ciclo verrà eseguito una sola volta, dato che la condizione è falsa. Trattandosi di un ciclo repeat-while, il corpo del ciclo verrà eseguito una volta prima che la condizione venga valutata.

var count = 2
repeat {
  print("\(count)…")
} while count < 0
print("Liftoff!")

Trasferimento del controllo

Swift ha una serie di istruzioni che possono essere usate per modificare il normale flusso di controllo dei cicli. Queste sono note come istruzioni di trasferimento del controllo. Hai già visto return; questo concetto ne introdurrà altre, tra cui continue, break e le etichette. Non tratteremo fallthrough in questo concetto, ma puoi trovarne una descrizione nel libro di Swift.

Continue

A volte è necessario passare anticipatamente all'iterazione successiva di un ciclo, senza completare il resto delle istruzioni dell'iterazione corrente del ciclo. La parola chiave continue può essere usata a questo scopo. Quando viene eseguito continue, il ciclo salta al controllo successivo per verificare se l'iterazione seguente del ciclo può essere eseguita, cioè il while nei cicli while e repeat-while, oppure il controllo della presenza di un altro elemento nella sequenza nei cicli for-in.

count = 1
while count < 6 {
  count += 1
  if count == 4 { continue }
  print(count)
}

// prints:
// 2
// 3
// 5

Break

break serve a uscire anticipatamente da un ciclo. Quando viene eseguito break, il ciclo termina immediatamente e il programma prosegue con la prima istruzione dopo il ciclo.

for fruit in ["banana", "grapes", "apple", "strawberry", "kiwi", "lemon"] {
  if !fruit.count.isMultiple(of: 2) { break }
  print(fruit)
}

// prints:
// banana
// grapes

Etichette

Quando i cicli sono annidati, a volte può servire usare break o continue per uscire o riavviare i cicli esterni che contengono il ciclo in cui break o continue vengono usati. In casi come questi, le etichette possono essere usate per specificare il ciclo da uscire o da riavviare. Un ciclo può essere etichettato mettendo un nome seguito da due punti prima del while, repeat o for che avvia il ciclo.

Per vedere l'effetto dell'uso delle etichette in questo modo, considera il seguente ciclo.

outerLoop: for fruit in ["banana", "grapes", "apple", "strawberry", "kiwi", "lemon"] {
  print("\n--- \(fruit) ---")
  for letter in fruit {
    guard letter != "n" else { break outerLoop }
    print(letter)
  }
}

// prints:
// --- banana ---
// b
// a

Istruzioni

Sei un esperto mixologist e prepari bevande gustose che il pubblico può godersi nelle sue serate fuori. Ma hai pensato che potevi semplificarti la vita scrivendo un po' di codice che ti aiutasse nel lavoro.

1. Determinare quanto tempo richiede preparare un ordine

Bevande diverse richiedono tempi di preparazione diversi:

  • "beer", "soda" e "water" richiedono 0,5 minuti ciascuna.
  • Gli "shot" richiedono 1,0 minuti, i "mixed drink" 1,5 minuti,
  • I "fancy drink" 2,5 minuti,
  • I "frozen drink" 3,0 minuti.

Implementa la funzione timeToPrepare(drinks:), che prende l'argomento drinks, un array di stringhe che rappresenta le bevande da preparare. La funzione deve restituire il tempo totale necessario per preparare tutte le bevande nell'array.

timeToPrepare(drinks: ["beer", "frozen drink", "shot"])
// returns 4.5

2. Rifornire la scorta di spicchi di lime

Una delle prime cose da fare quando inizi il turno è assicurarti che il contenitore degli spicchi di lime sia pieno per il turno che ti aspetta. Avrai lime di dimensioni diverse, che daranno un numero diverso di spicchi: da un lime "small" puoi ricavare 6 spicchi, da uno "medium" 8 spicchi e da uno "large" 10.

Finché ti servono ancora spicchi e hai ancora lime da tagliare, prendi il primo lime dall'array e sottrai dalla quantità che ti serve il numero di spicchi corrispondente. Continua finché non ti servono più spicchi o finché non finisci i lime.

Implementa la funzione makeWedges(needed:limes:), che prende gli argomenti needed, il numero di spicchi che devi ricavare, e limes, un array di stringhe che rappresenta le dimensioni dei lime che hai a disposizione per tagliarli. La funzione deve restituire il numero di lime che hai tagliato.

makeWedges(needed: 25, limes: ["small", "small", "large", "medium", "small"])
// returns 4

3. Concludere il turno

Congratulazioni! La tua lunga giornata di lavoro è quasi finita e tra poco andrai a casa a lavorare alla tua nuova app. Ma hai ancora una serie di ordini di bevande da preparare prima di poter passare le ordinazioni al turno successivo e andartene.

Finché ti resta tempo nel turno, prepara il primo ordine dell'array e poi rimuovi quell'ordine dall'array. Poi puoi sottrarre dal tempo che ti resta nel turno il tempo impiegato per preparare quell'ordine, secondo la tua funzione timeToPrepare(drinks:).

Implementa la funzione finishShift(minutesLeft:remainingOrders:), che prende il numero di minuti che restano nel tuo turno (garantito maggiore di 0) e un array non vuoto di ordini di bevande. La funzione deve restituire l'array degli ordini che non hai ancora preparato prima della fine del turno.

finishShift(minutesLeft: 5, remainingOrders: [["beer", "frozen drink", "shot"], ["fancy drink", "soda"], ["beer", "beer", "water"], ["mixed drink", "frozen drink"]])
// returns [["beer", "beer", "water"], ["mixed drink", "frozen drink"]]

4. Tenere traccia di certi ordini

Per assicurarti che beer e soda restino freschi, devi tenere traccia dei loro ordini insieme agli orari in cui sono stati effettuati.

Implementa la funzione orderTracker(orders: [(drink: String, time: String)]) -> (beer: (first: String, last: String, total: Int)?, soda: (first: String, last: String, total: Int)?) che, data una lista di ordini e di orari, restituisce una coppia di tuple opzionali contenenti gli orari del primo e dell'ultimo ordine di beer e di soda, il numero totale di ordini di ciascuno, e nil se non è stato effettuato alcun ordine per quelle bevande. Non devi tenere traccia di nessun'altra bevanda.

Implementa la funzione orderTracker(orders:), che prende un array di tuple, dove ogni tupla contiene la bevanda ordinata e l'orario in cui l'ordine è stato effettuato. La funzione deve restituire una tupla contenente l'orario del primo e dell'ultimo ordine di beer, il numero totale di ordini di beer, l'orario del primo e dell'ultimo ordine di soda e il numero totale di ordini di soda. Deve essere restituita come una tupla nel formato: (beer: (first: String, last: String, total: Int)?, soda: (first: String, last: String, total: Int)?).

let orders = [
    (drink: "beer", time: "10:01"), (drink: "frozen drink", time: "10:02"),
    (drink: "shot", time: "10:05"), (drink: "fancy drink", time: "10:06"),
    (drink: "soda", time: "10:09"), (drink: "beer", time: "10:15"), (drink: "beer", time: "10:22"),
    (drink: "water", time: "10:26"), (drink: "mixed drink", time: "10:28"),
    (drink: "frozen drink", time: "10:33"),
]

orderTracker(orders: orders)

// returns (beer: (first "10:01", last "10:22", total 3), soda: (first "10:09", last "10:09", total 1))
Modifica tramite GitHub Il link si apre in una nuova finestra o scheda
Swift Exercism

Vuoi iniziare Esperto mixologo?

Iscriviti a Exercism per imparare e padroneggiare Swift con 35 concetti116 esercizi e il mentoring di persone reali, tutto gratis.