switch() 函式可以簡潔地取代一長串 if ... else if 的比較。
切換所依據的變數最常見的是字串,若是字串,選擇器中的引號就可以省略。
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 型別時,最後一個值是預設值,就像這裡這樣。
使用整數型別時,則無法指定預設值。
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 的一部分。
在這個練習中,我們要模擬一場二十一點遊戲的第一回合。
你會拿到兩張牌,也能看到莊家翻開的那張牌。所有牌都用字串表示,例如 "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 | other | 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"