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 敘述。
最後一個值可以和這裡一樣是預設值,也可以是 stop();若這些條件預期要窮盡所有情況,就會拋出錯誤。
對整數進行 switch 則略有不同:這時的預設值一律是 NULL(這會在虛無概念中討論)。
dplyr中的函式base R 中的 switch相當有限:它只能對單一輸入做完全相符的比對。
R 在 1993 年首次發布時,這樣的設計看似合理,但以現代用途來說需要改良。
如同 Conditionals概念中提到的,tidyverse套件集合的設計目的,是在不影響向後相容性的前提下補充(有時甚至取代)base R 的功能。
tidyverse 套件也有很出色、很現代的說明文件,所以點擊下面的連結可以了解更多細節。
只要在程式碼開頭加上 library(dplyr)(載入單一套件)或 library(tidyverse)(載入整個集合),就能把 dplyr套件納入作用域。
dplyr套件提供了兩個與 switch相關的額外函式。
recode_values與replace_values函式這兩個相關的函式可以像 switch 一樣做向量化的對應,把舊值轉成新值。
兩者最大的差別在於:recode_values()會建立一個全新的向量,而 replace_values()則允許局部更新既有的向量。
比對仍然必須完全相符,但有以下幾點不同:
~ 連結,而不是用 =。NA 可以明確比對(這會在虛無概念中討論)。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_match() 函式來當作向量化的 switch。
這個函式已在 dplyr 1.2.0 版(2026 年 2 月)中棄用。
現在嘗試使用它會產生警告訊息,建議改用 recode_values()。
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。
字串函式已經討論過,正規表達式則會是之後某個概念的主題。
這些都很適合與 case_when搭配使用。
library(stringr)
tracks <- "R C Python C# Elixir C++ Odin" |> str_split_1(" ")
tracks
#> [1] "R" "C" "Python" "C#" "Elixir" "C++" "Odin"
case_when(
str_starts(tracks, "C") ~ "C-like",
str_starts(tracks, "[AEIOU]") ~ "vowel",
.default = "other"
)
#> [1] "other" "C-like" "other" "C-like" "vowel" "C-like" "vowel"