Percursos
/
Swift
Swift
/
Exercícios
/
Mixologista especialista
Mixologista especialista

Mixologista especialista

Exercício de aprendizagem

Introdução

Switch

Uma instrução switch permite-te comparar um valor com vários valores possíveis. Permite-te escrever código mais conciso do que se usares várias condicionais else-if. Uma instrução switch começa com a palavra-chave switch, seguida do valor a comparar. Depois, podes definir os casos com a palavra-chave case, seguida do valor com que queres comparar. A palavra-chave default serve para definir o caso por omissão, quando nenhum dos casos corresponde. Tal como as condicionais else-if, as instruções switch só executam o bloco de código associado ao primeiro caso que corresponde.

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

Considera o seguinte exemplo:

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

Em vez disso, podíamos escrever:

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

Ciclos while

Um ciclo while é uma instrução de controlo de fluxo que permite executar código enquanto uma determinada condição for verdadeira. O Swift disponibiliza dois tipos de ciclos while: os ciclos while e os ciclos repeat-while. A condição do ciclo while é avaliada antes de o corpo do ciclo ser executado; se a condição for falsa, o corpo do ciclo não chega a ser executado. Os ciclos while em Swift têm a seguinte estrutura:

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

Aqui, o ciclo é executado enquanto o count for maior que 0 e imprime assim os números 2 e 1 e a palavra "Liftoff!".

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

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

Um ciclo repeat-while é semelhante a um ciclo while, mas a condição é avaliada depois de o corpo do ciclo ser executado. Isto significa que o corpo do ciclo é sempre executado pelo menos uma vez, mesmo que a condição seja falsa. Os ciclos repeat-while em Swift têm a seguinte estrutura:

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

Aqui, o ciclo só é executado uma vez, porque a condição é falsa. Como é um ciclo repeat-while, o corpo do ciclo é executado uma vez antes de a condição ser avaliada.

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

Transferência de controlo

O Swift tem um conjunto de instruções que permitem alterar o fluxo de controlo normal dos ciclos. São conhecidas como instruções de transferência de controlo. Já viste o return; este conceito vai apresentar outras, incluindo o continue, o break e os rótulos. Não vamos abordar o fallthrough neste conceito, mas podes ler sobre ele no livro do Swift.

Continue

Por vezes, é necessário saltar antecipadamente para a iteração seguinte de um ciclo, sem completar o resto das instruções da iteração atual do ciclo. Para isso, podes usar a palavra-chave continue. Quando o continue é executado, o ciclo passa para a verificação seguinte, para ver se a iteração seguinte do ciclo pode ser executada, ou seja, o while nos ciclos while e repeat-while ou a verificação de se há mais um elemento na sequência, nos ciclos for-in.

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

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

Break

O break serve para sair de um ciclo mais cedo. Quando o break é executado, o ciclo termina de imediato e o programa continua com a primeira instrução depois do ciclo.

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

// prints:
// banana
// grapes

Rótulos

Quando os ciclos estão aninhados, há alturas em que podemos querer usar break ou continue para sair ou reiniciar os ciclos exteriores que contêm o ciclo em que o break ou o continue são usados. Em casos como estes, podemos usar rótulos para indicar o ciclo que queremos terminar ou reiniciar. Podemos dar um rótulo a um ciclo colocando um nome seguido de dois pontos antes do while, do repeat ou do for que inicia o ciclo.

Para veres o efeito de usar rótulos desta forma, repara no ciclo seguinte.

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

Instruções

És um mixologista experiente e preparas bebidas saborosas para o público apreciar nas suas noites de saída. Mas pensaste que podias tornar a tua vida mais fácil se escrevesses um pouco de código para te ajudar no trabalho.

1. Determina quanto tempo demora a preparar um pedido

Bebidas diferentes demoram tempos diferentes a preparar:

  • "beer", "soda" e "water" demoram 0,5 minutos cada.
  • Os "shot" demoram 1,0 minutos e os "mixed drink" demoram 1,5 minutos,
  • Os "fancy drink" demoram 2,5 minutos,
  • Os "frozen drink" demoram 3,0 minutos.

Implementa a função timeToPrepare(drinks:), que recebe o argumento drinks, o qual contém um array de strings que representam as bebidas a preparar. A função deve devolver o tempo total necessário para preparar todas as bebidas do array.

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

2. Reabastece a tua reserva de gomos de lima

Uma das primeiras coisas que tens de fazer quando começas o turno é garantir que o teu caixote de gomos de lima está cheio para o turno que se segue. Vais ter limas de tamanhos diferentes, que dão quantidades diferentes de gomos: consegues 6 gomos de uma lima "small", 8 gomos de uma lima "medium" e 10 de uma lima "large".

Enquanto ainda precisares de mais gomos e ainda tiveres limas para cortar, retira a primeira lima do array e subtrai o número adequado de gomos à quantidade de que precisas. Continua até já não precisares de mais gomos ou até acabarem as limas.

Implementa a função makeWedges(needed:limes:), que recebe os argumentos needed, que contém o número de gomos que precisas de cortar, e limes, que contém um array de strings que representam os tamanhos das limas que tens disponíveis para cortar. A função deve devolver o número de limas que cortaste.

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

3. Termina o teu turno

Parabéns! O teu longo dia de trabalho está quase a acabar e em breve vais para casa trabalhar na tua nova aplicação. Mas ainda tens uma série de pedidos de bebidas para preparar antes de passares os pedidos ao turno seguinte e ires embora.

Enquanto ainda tiveres tempo no teu turno, prepara o primeiro pedido do array e remove depois esse pedido do array. Podes então subtrair ao tempo que resta do teu turno o tempo que demorou a preparar esse pedido, de acordo com a tua função timeToPrepare(drinks:).

Implementa a função finishShift(minutesLeft:remainingOrders:), que recebe o número de minutos que restam do teu turno (garantidamente superior a 0) e um array não vazio de pedidos de bebidas. A função deve devolver o array dos pedidos que ainda não conseguiste preparar antes do fim do teu 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. Regista determinados pedidos

Para garantir que a beer e a soda se mantêm frescas, precisas de acompanhar os pedidos de ambas, juntamente com as horas a que foram feitos.

Implementa a função orderTracker(orders: [(drink: String, time: String)]) -> (beer: (first: String, last: String, total: Int)?, soda: (first: String, last: String, total: Int)?) que, dada uma lista de pedidos e de horas, devolve um par de tuplos opcionais com as horas do primeiro e do último pedido de beer e de soda, juntamente com o número total de pedidos de cada uma, e nil se não tiver sido feito nenhum pedido dessas bebidas. Não precisas de acompanhar mais nenhuma bebida.

Implementa a função orderTracker(orders:), que recebe um array de tuplos, em que cada tuplo contém a bebida pedida e a hora a que o pedido foi feito. A função deve devolver um tuplo com a primeira e a última hora a que foi pedido beer, o número total de pedidos de beer, a primeira e a última hora a que foi pedido soda e o número total de pedidos de soda. Deve ser devolvido como um tuplo com o 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))
Editar via GitHub A ligação abre numa nova janela ou separador
Swift Exercism

Estás pronto para começar Mixologista especialista?

Inscreve-te no Exercism para aprenderes e dominares Swift com 35 conceitos116 exercícios, e mentoria humana real, tudo grátis.