switch()函数可以简洁地替代一长串 if ... else if 判断。
用于 switch 的变量通常是一个字符串,这种情况下,选择器里可以省略引号。
star <- function(type) {
switch(type,
M = , # will "fall through" if no value given
K = "red dwarf",
G = "Earth-like",
"bigger star" # only correct for O,B,A,F
)
}
> star("M")
[1] "red dwarf"
注意,只有像上面例子中的 M 那样把值留空时,选项才会向下穿透。
不像其他一些语言那样,这里不需要写 break 语句。
对 character 类型进行 switch 时,最后一个值就是默认值,就像这里一样。
而对于整数类型,则无法指定默认值。
dplyr中的函数base R 中的switch相当有限:它只能对单个输入做精确匹配。
在 1993 年 R 首次发布时,这看起来很合理,但按现代的使用需求,它还有待改进。
正如Conditionals概念中提到的,tidyverse系列包的设计宗旨是补充(有时是替代)base R 的功能,同时不影响向下兼容。
只需在代码顶部加上library(dplyr)(用于单个包)或library(tidyverse)(用于整个系列),就能把dplyr包引入作用域。
dplyr库提供了两个与switch相关的额外函数。
recode_values和replace_values函数这两个相关的函数可以把旧值以类似 switch 的、向量化的方式映射为新值。
它们的主要区别在于,recode_values()会创建一个全新的向量,而replace_values()允许对已有向量做部分更新。
匹配仍然是精确匹配,不过:
~连接,而不是=。library(dplyr)
x <- c("a", "b", "a", "d", "b", NA, "c", "e", "z")
recode_values(
x,
"a" ~ 1,
"b" ~ 2,
"c" ~ 3,
c("d", "e") ~ 4, # either "d' or "e" will match
NA ~ 0, # matches missing values
default = 100 # note the different syntax for the default
)
#> [1] 1 2 1 4 2 0 3 4 100
case_when函数case_when把case_match的语法又推进了一步:它允许在~左侧写任意逻辑表达式。
输入向量(下面例子中的x)不是作为实参传入的,它只需要已经定义好。
x <- 1:10
case_when(
x < 3 ~ "low",
between(x, 3, 5) ~ "mid",
between(x, 6, 8) ~ "high",
.default = "what?"
)
#> [1] "low" "low" "mid" "mid" "mid" "high" "high" "high" "what?" "what?"
between()函数也是dplyr的一部分。
在这个练习中,我们要模拟一局21 点游戏的第一回合。
你会拿到两张牌,并且可以看到庄家的明牌。所有牌都用字符串表示,例如 “ace”、“king”、“three”、“two” 等。每张牌的值如下:
| 牌 | 值 | 牌 | 值 |
|---|---|---|---|
| ace | 11 | eight | 8 |
| two | 2 | nine | 9 |
| three | 3 | ten | 10 |
| four | 4 | jack | 10 |
| five | 5 | queen | 10 |
| six | 6 | king | 10 |
| seven | 7 | 其他 | 0 |
注意:通常 ace 的值可以是 1 或 11,但为了简单起见,我们假设它只能取 11。
根据你的两张牌和庄家的牌,游戏的第一回合有一套策略,你有以下几种选择:
这套策略虽然还不是最优的,但你要按照你的朋友 Alex 一直在制定的策略来做,具体如下:
实现一个函数 parse_card,用来计算一张牌的值:
parse_card("ace")
# => 11
写一个函数 first_turn,实现上面描述的决策逻辑:
first_turn(card1, card2, dealer_card)
下面是几个预期结果的例子:
first_turn("ace", "ace", "jack") == "P"
first_turn("ace", "king", "ace") == "S"
first_turn("five", "queen", "ace") == "H"