轨道
/
Swift
Swift
/
练习
/
专业调酒师
专业调酒师

专业调酒师

学习练习

简介

switch语句

switch语句让你可以把一个值与多个可能的匹配值进行比较,从而写出比使用多个else-if语句更简洁的代码。switch语句以switch关键字开头,后面跟着要比较的值。然后你可以用case关键字定义各个分支,后面跟着要与之比较的值。当所有分支都不匹配时,用default关键字定义默认分支。和else-if语句一样,switch语句只会执行第一个匹配分支所对应的代码块。

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

看看下面这个例子:

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

也可以改写成这样:

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

while循环

while循环是一种控制流语句,它让代码在某个条件为真时反复执行。Swift 提供了两种 while 循环:while循环和repeat-while循环。while循环会先对条件求值,再执行循环体;如果条件为假,循环体根本不会执行。Swift 中while循环的结构如下:

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

这里的循环会在 count 大于 0 时一直执行,因此会依次打印出数字 2、1 和“Liftoff!”。

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

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

repeat-while循环与while循环类似,但它的条件是在循环体执行之后才求值。这意味着即使条件为假,循环体也至少会执行一次。Swift 中repeat-while循环的结构如下:

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

这里的循环只会执行一次,因为条件为假。由于它是repeat-while循环,循环体会先执行一次,然后才对条件求值。

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

控制转移

Swift 提供了一组语句,可以用来改变循环正常的控制流。这些语句称为控制转移语句。你已经见过return了;本概念会介绍其他几种,包括continue、break和标签。本概念不会讲解fallthrough,但你可以在 Swift 官方书籍中了解它。

continue

有时需要提前跳到循环的下一次迭代,而不执行本次迭代中剩下的语句。这时可以使用continue关键字。执行continue时,循环会跳到下一次检查,判断下一次迭代能否执行,也就是while循环和repeat-while循环中的那个while,或者for-in循环中判断序列里是否还有下一个元素。

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

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

break

break用于提前退出循环。执行break时,循环会立即退出,程序接着执行循环之后的第一条语句。

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

// prints:
// banana
// grapes

标签

当循环嵌套时,有时你会想用break或continue退出或重新开始外层循环,也就是包含break或continue所在循环的那些循环。在这种情况下,可以用标签来指定要退出或重新开始的循环。在循环开头的while、repeat或for前面写上一个名字加冒号,就可以给循环加上标签。

想看看这样使用标签的效果,请看下面这个循环。

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

说明

你是一名专业的调酒师,为客人们调制美味的饮品,让他们在夜晚外出时尽情享用。不过你想,写点代码来帮自己完成工作,也许能让日子轻松一些。

1. 判断完成一笔订单需要多长时间

不同的饮品需要的准备时间各不相同:

  • "beer"、"soda"和"water"各需要 0.5 分钟。
  • "shot"需要 1.0 分钟,"mixed drink"需要 1.5 分钟,
  • "fancy drink"需要 2.5 分钟,
  • "frozen drink"需要 3.0 分钟。

实现函数 timeToPrepare(drinks:),它接收参数 drinks,该参数是一个字符串数组,表示需要准备的饮品。 函数应返回准备数组中所有饮品所需的总时间。

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

2. 补充你的青柠角储备

开始一个班次时要做的头几件事之一,就是确保你那一小盒青柠角在接下来的班次里是满的。 青柠大小不同,切出的青柠角数量也不同:一个 "small" 青柠能切出 6 个青柠角,一个 "medium" 青柠能切出 8 个,一个 "large" 青柠能切出 10 个。

当你还需要更多青柠角,而手里也还有青柠可以切时,就从数组中取出第一个青柠,并从你还需要的数量中减去相应数量的青柠角。 一直继续,直到你不再需要青柠角,或者青柠用完为止。

实现函数 makeWedges(needed:limes:),它接收参数 needed(你需要切出的青柠角数量)和 limes(一个字符串数组,表示你可用来切青柠的青柠大小)。 函数应返回你切了多少个青柠。

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

3. 结束你的班次

恭喜!漫长的一天工作快结束了,你很快就能回家去开发你的新应用。不过在你把订单交接给下一个班次、然后离开之前,还有一连串的饮品订单要做。

只要班次里还有剩余时间,你就先处理数组中的第一笔订单,然后把该订单从数组中移除。 接着,根据你的函数 timeToPrepare(drinks:),从班次的剩余时间中减去准备这笔订单所花的时间。

实现函数 finishShift(minutesLeft:remainingOrders:),它接收班次剩余的分钟数(保证大于 0)和一个非空的饮品订单数组。 函数应返回在班次结束前你还没处理到的订单数组。

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. 追踪特定的订单

为了确保啤酒和汽水保持新鲜,你需要追踪它们的订单以及下单的时间。

实现函数 orderTracker(orders: [(drink: String, time: String)]) -> (beer: (first: String, last: String, total: Int)?, soda: (first: String, last: String, total: Int)?),当给定订单和时间的列表时,返回一对可选元组,其中包含啤酒和汽水第一笔和最后一笔订单的时间,以及各自的订单总数;如果这些饮品没有订单,则为 nil。你不需要追踪其他饮品。

实现函数 orderTracker(orders:),它接收一个元组数组,每个元组包含所点的饮品和下单时间。 函数应返回一个元组,其中包含啤酒第一笔和最后一笔订单的时间、啤酒订单总数、汽水第一笔和最后一笔订单的时间,以及汽水订单总数。 返回的元组格式为:(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))
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Swift Exercism

准备好开始 专业调酒师 了吗?

注册 Exercism,借助 35 个概念116 个练习 和真人导师指导,学习并掌握 Swift,全部免费。