Parcours
/
Swift
Swift
/
Exercices
/
Expert en mixologie
Expert en mixologie

Expert en mixologie

Exercice d'apprentissage

Introduction

L'instruction switch

Une instruction switch permet de comparer une valeur à plusieurs valeurs correspondantes possibles. Elle permet d'écrire du code plus concis qu'en enchaînant plusieurs instructions else-if. Une instruction switch commence par le mot-clé switch, suivi de la valeur à comparer. On définit ensuite les cas avec le mot-clé case, suivi de la valeur à laquelle se comparer. Le mot-clé default sert à définir le cas par défaut, lorsque aucun des cas ne correspond. Comme les instructions else-if, les instructions switch n'exécutent que le bloc de code associé au premier cas qui correspond.

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

Prenons l'exemple suivant :

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.")
}

On pourrait plutôt l'écrire comme ceci :

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.")
}

Les boucles while

Une boucle while est une instruction de contrôle de flux qui permet d'exécuter du code tant qu'une certaine condition est vraie. Swift propose deux sortes de boucles while : les boucles while et les boucles repeat-while. La condition d'une boucle while est évaluée avant l'exécution du corps de la boucle ; si la condition est fausse, le corps de la boucle ne sera pas exécuté du tout. Les boucles while en Swift ont la structure suivante :

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

Ici, la boucle s'exécute tant que count est supérieur à 0, et affiche donc les nombres 2, 1 et « Liftoff! ».

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

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

Une boucle repeat-while est semblable à une boucle while, mais la condition est évaluée après l'exécution du corps de la boucle. Cela signifie que le corps de la boucle s'exécute toujours au moins une fois, même si la condition est fausse. Les boucles repeat-while en Swift ont la structure suivante :

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

Ici, la boucle ne s'exécute qu'une seule fois, puisque la condition est fausse. Comme il s'agit d'une boucle repeat-while, le corps de la boucle s'exécute une fois avant que la condition ne soit évaluée.

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

Le transfert de contrôle

Swift dispose d'un ensemble d'instructions qui permettent de modifier le déroulement normal des boucles. On les appelle les instructions de transfert de contrôle. Tu as déjà vu return ; ce concept en présente d'autres, notamment continue, break et les étiquettes. On ne traite pas de fallthrough dans ce concept, mais tu peux en lire plus dans le livre Swift.

Continue

Il est parfois nécessaire de passer directement à l'itération suivante d'une boucle, sans exécuter le reste des instructions de l'itération en cours. Le mot-clé continue permet de le faire. Lorsque continue est exécuté, la boucle passe à la vérification suivante pour savoir si l'itération suivante peut avoir lieu, c'est-à-dire le while des boucles while et repeat-while, ou la vérification de la présence d'un autre élément dans la séquence, pour les boucles for-in.

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

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

Break

L'instruction break sert à sortir d'une boucle de façon anticipée. Lorsque break est exécuté, la boucle se termine immédiatement et le programme poursuit avec la première instruction qui suit la boucle.

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

// prints:
// banana
// grapes

Étiquettes

Lorsque des boucles sont imbriquées, il arrive que l'on veuille utiliser break ou continue pour sortir ou redémarrer une boucle externe qui contient la boucle dans laquelle break ou continue est utilisé. Dans ce genre de cas, on peut utiliser des étiquettes pour préciser la boucle à quitter ou à redémarrer. On peut étiqueter une boucle en plaçant un nom suivi de deux-points devant le while, le repeat ou le for qui débute la boucle.

Pour voir l'effet d'étiquettes utilisées de cette façon, considère la boucle suivante.

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

Instructions

Tu es un expert en mixologie, et tu prépares de délicieux cocktails que le public savoure lors de ses soirées. Mais tu t'es dit que tu pourrais te faciliter la vie en écrivant un peu de code pour t'aider dans ton travail.

1. Détermine combien de temps il faut pour préparer une commande

Les différentes boissons demandent un temps de préparation différent :

  • "beer", "soda" et "water" prennent 0,5 minute chacune.
  • les "shot" prennent 1,0 minute, les "mixed drink" prennent 1,5 minute,
  • les "fancy drink" prennent 2,5 minutes,
  • les "frozen drink" prennent 3,0 minutes.

Implémente la fonction timeToPrepare(drinks:), qui prend l'argument drinks, un tableau de strings représentant les boissons à préparer. La fonction doit renvoyer le temps total nécessaire pour préparer toutes les boissons du tableau.

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

2. Réapprovisionne ta réserve de quartiers de citron vert

L'une des premières choses à faire au début de ton service est de t'assurer que ta petite boîte de quartiers de citron vert est bien pleine pour le service à venir. Tu disposes de citrons verts de différentes tailles, qui donnent un nombre différent de quartiers : un citron "small" donne 6 quartiers, un "medium" en donne 8 et un "large" en donne 10.

Tant que tu as encore besoin de quartiers et qu'il te reste des citrons à découper, prends le premier citron du tableau et soustrais le nombre de quartiers correspondant à la quantité dont tu as besoin. Continue ainsi jusqu'à ce que tu n'aies plus besoin de quartiers ou qu'il ne te reste plus de citrons.

Implémente la fonction makeWedges(needed:limes:), qui prend les arguments needed, le nombre de quartiers que tu dois découper, et limes, un tableau de strings représentant les tailles des citrons verts que tu as à découper. La fonction doit renvoyer le nombre de citrons que tu as découpés.

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

3. Termine ton service

Bravo ! Ta longue journée de travail touche à sa fin et tu rentreras bientôt chez toi pour travailler sur ta nouvelle application. Mais il te reste encore une série de commandes de boissons à préparer avant de pouvoir les transmettre à l'équipe suivante et partir.

Tant qu'il te reste du temps dans ton service, prépare la première commande du tableau, puis retire cette commande du tableau. Tu peux ensuite soustraire le temps qu'a pris la préparation de cette commande, selon ta fonction timeToPrepare(drinks:), du temps restant dans ton service.

Implémente la fonction finishShift(minutesLeft:remainingOrders:) qui prend le nombre de minutes restantes dans ton service (garanti supérieur à 0) et un tableau non vide de commandes de boissons. La fonction doit renvoyer le tableau des commandes que tu n'as pas encore eu le temps de préparer avant la fin de ton service.

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. Suis certaines commandes

Pour t'assurer que la bière et le soda restent frais, tu dois suivre leurs commandes ainsi que les heures auxquelles ces commandes ont été passées.

Implémente la fonction orderTracker(orders: [(drink: String, time: String)]) -> (beer: (first: String, last: String, total: Int)?, soda: (first: String, last: String, total: Int)?) qui, étant donné une liste de commandes et d'heures, renvoie une paire de tuples optionnels contenant les heures de la première et de la dernière commande de bière et de soda, ainsi que le nombre total de commandes de chacune, et nil si aucune commande de ces boissons n'a été passée. Tu n'as pas besoin de suivre les autres boissons.

Implémente la fonction orderTracker(orders:) qui prend un tableau de tuples, où chaque tuple contient la boisson commandée et l'heure à laquelle la commande a été passée. La fonction doit renvoyer un tuple contenant l'heure de la première et de la dernière commande de bière, le nombre total de commandes de bière, l'heure de la première et de la dernière commande de soda, et le nombre total de commandes de soda. Il doit être renvoyé sous la forme d'un tuple au format : (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))
Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet
Swift Exercism

Prêt à commencer Expert en mixologie ?

Inscris-toi sur Exercism pour apprendre et maîtriser Swift avec 35 concepts116 exercices, et un vrai mentorat humain, le tout gratuitement.