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の関数Rの基本機能にあるswitchはかなり限定的で、1つの入力に対する完全一致しか行えません。
1993年にRが最初にリリースされた当時は合理的でしたが、現代の使い方には改善が必要です。
Conditionalsのコンセプトで触れたように、tidyverseはパッケージを集めたもので、後方互換性に影響を与えずにRの基本機能を補完する(ときに置き換える)ように設計されています。
dplyrパッケージをスコープに入れるには、コードの先頭にlibrary(dplyr)(1つのパッケージだけを使う場合)かlibrary(tidyverse)(コレクション全体を使う場合)のどちらかを追加します。
dplyrライブラリには、switchに関連する2つの追加関数があります。
recode_values関数とreplace_values関数これら2つのよく似た関数は、古い値から新しい値への、ベクトル化された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の一部です。
この演習では、ブラックジャックのゲームの最初のターンをシミュレートします。
2枚のカードを受け取り、ディーラーの表向きのカードを見ることができます。カードはすべて、"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 |
注意:一般的に、エースは1または11の値を取ることができますが、簡単にするために、ここでは11の値しか取らないものとします。
手元の2枚のカードとディーラーのカードに応じて、ゲームの最初のターンで取るべき戦略が決まります。選択肢は次のとおりです。
まだ最適とは言えませんが、ここでは友人の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"