Rには、他の多くの言語と同じ演算子がそろっています。
1 == 2 # FALSE
1 != 2 # TRUE
1 < 2 # TRUE
1 > 2 # FALSE
1 <= 2 # TRUE
1 >= 2 # FALSE
if-then-elseの基本的な形は次のとおりです。
if (x > 10) {
y <- "big"
} else if (x > 2) {
y <- "medium"
} else {
y <- "tiny"
}
この場合、条件を囲む丸括弧(( ))と、本体を囲む波括弧({ })の両方が必要です。
単純なif文は短く書けます。
if (x == 0) return("success")
この先のvector-filteringコンセプトを見据えておきましょう。括弧(())の中の条件式は、単一のTRUE/FALSEに評価される必要があります。
比較にベクトルを含めると、たいていは真偽値のベクトルが返るので、all()(すべての値がTRUEか?)やany()(少なくとも1つの値がTRUEか?)のような集約関数で包む必要があります。
numbers <- c(4,5,7,9,10,11)
numbers %% 3 == 0 # gives vector of booleans
#> [1] FALSE FALSE FALSE TRUE FALSE FALSE
# use any() to get a single TRUE/FALSE
if (any(numbers %% 3 == 0)) print("1 or more numbers are divisible by 3")
#> [1] "1 or more numbers are divisible by 3"
ifelse関数結果がtrueかfalseのどちらかにしかならないのであれば、代わりのif-elseの形が役立つことがあります。
y <- ifelse(x > 8, "big", "small")
# Don't mix result types:
z <- ifelse(x > 100, 100, "small") # numeric or string result? Expect problems!
ifelse()はちょうど3つの入力を取ります。
TRUEのときの値FALSEのときの値。ベクトルを入力してもよく、その場合はベクトルが出力されます。
この場合、どちらの分岐も同じ型のデータ(数値、文字列、論理値など)になるようにしてください。
これについては、vector-functionsコンセプトで扱います。
2つの結果(上の例では"big", "small")は、それぞれ単一の値にしてください。
残念ながら、ここにより長いベクトルを渡すと、警告メッセージも出ないまま、Rが紛らわしく予想外の動作をすることがあります。
if_else関数R言語のメンテナーは、できるだけ破壊的変更を避けるという方針を取っています。 これは、CRANにある膨大な数のサードパーティパッケージを維持するのに役立ちますが、base Rを現代的なプログラミングの考え方で更新する余地を狭めています。
近年、Rの機能を拡張し、ときに置き換えるパッケージがいくつか公開されています。これらは、元々のRの設計の長所と短所について何十年にもわたる経験に基づいています。
これらのパッケージは、tidyverseというコレクションを構成しています。
これらは2023年にExercismのテストランナーに追加され、演習で使えるようになりました。
Rトラックは、tidyverseが追加されるより数年早くからあるので、多くのコミュニティの解答がベース言語にこだわっていることに気づくかもしれません。
dplyrパッケージdplyrは、主にデータフレームを操作するためのものです(コースの後半で扱います)。
コードの先頭にlibrary(dplyr)と書くか、コレクション全体を追加するlibrary(tidyverse)を使います。
名前のマスクに関する警告メッセージが表示されることがありますが、めったに問題にはなりません。
今回のコンセプトでは、if_else関数が注目に値します。
これは、base Rのifelseとほとんど同じです。
library(dplyr) # warnings not shown
x <- 10
if_else(x > 8, "big", "small")
#> [1] "big"
主な違いは、if_elseが4番目の入力をオプションで取れることです。これは、RでNAとして表される欠損値のためです。
xs <- c(3, NA, 10, NA, 4) # a 5-element vector
xs
#> [1] 3 NA 10 NA 4
if_else(xs > 8, "big", "small", "missing")
#> [1] "small" "missing" "big" "missing" "small"
# contrast:
ifelse(xs > 8, "big", "small")
#> [1] "small" NA "big" NA "small"
また、if_elseのほうが古いifelseよりエラーメッセージがはるかに親切だと感じるかもしれません。
dplyrライブラリを読み込むと、between()関数も使えるようになります。
Rでは比較をつなげて書くことができないので、1 <= x <= 5と書くとエラーメッセージが出ます。
dplyrを読み込んでいれば、between(x, 1, 5)はx >= 1 & x <= 5と同じで、より読みやすいかもしれません。
下限も上限も、その値を含みます。