4  条件判断(Control structures)

4.1 条件判断とは?

プログラミングでは、ある条件のときはこの処理、別の条件のときはこの処理…、といった具合に、条件によって行う処理を変えたいことがよくあります。例えば、じゃんけんでは出した手の条件によって勝ち・負け・引き分けという3つの処理を行うことになります。このように、条件によって処理を変えることを、条件判断と呼びます。

4.2 条件と論理型(logical)

条件として用いられるのは、論理型(logical)です。論理型はTRUE(真)とFALSE(偽)の2つの値を持ちます。論理型はそれそのものを用いる場合と、比較演算子の演算結果として得る場合があります。Rでは、TRUETFALSEFと表記することができます。

論理型
TRUE
## [1] TRUE

FALSE
## [1] FALSE

T
## [1] TRUE

F
## [1] FALSE

c(T, F, T, F) # logicalはベクターにもできる
## [1]  TRUE FALSE  TRUE FALSE

1 < 3 # 3は1より大きいのでTRUE
## [1] TRUE

1 > 3 # 1は3より大きくないのでFALSE
## [1] FALSE

4.3 数値としての論理型

論理型は、Rの内部では数字として取り扱われています。RではTRUE1FALSE0と同一です。ですので、ベクター中のTRUEの数を足し算で計算することができます。また、0以外がTRUE0FALSEとして扱われる場合もあります。条件判断では0FALSEとして用いる場合もあります。

数値としての真偽値
T + T + F # 足し算すると2が返ってくる
## [1] 2

vec <- c(T, T, F, T, F, T, F)
sum(vec) # sumはベクターの要素を足し算する関数
## [1] 4

RではTRUEが1、FALSEが0ですが、他の言語ではFALSEが-1のものもあります。言語によりTRUE/FALSEの仕様は異なります。

4.4 論理演算子

論理型は、論理演算子による計算に使うことができます。Rでの論理演算子は&&&|||の4つです。このうち、&&||は、ベクターの始めの値だけを評価するという特徴を持っています(Rのバージョン4.3以降ではベクターを比較するとエラーが出ます)。&&||を用いるとプログラムが予想外の挙動を取ることがあるので、できるだけ&|だけを用いたほうがよいでしょう。RにはNAND(否定論理積)、NOR(否定論理和)などを表す専用の論理演算子はありませんが、XOR(排他的論理和)を表す関数(xor関数)はあります。XORは2つの論理型に対し、どちらかがTRUEならTRUEを、両方がFALSEならFALSEを返す演算子です。

表1:Rで使える論理演算子
論理演算子 演算子の意味
& 論理積(AかつB)
&& 論理積(ベクターの始めの要素のみ評価)
| 論理和(AまたはB)
|| 論理和(ベクターの始めの要素のみ評価)
! 否定演算子(真偽を反転)
xor 排他的論理和
any いずれかが真の時に真を返す
all すべてが真の時に真を返す
論理演算子による演算
logic1 <- c(T, F)
logic2 <- c(F, F)
logic1 & logic2 # & は論理積(AND)
## [1] FALSE FALSE

logic1 | logic2 # | は論理和(OR)
## [1]  TRUE FALSE

logic1 && logic2 # 1番目の項目同士のみを比較する
## Error in logic1 && logic2: 'length = 2' in coercion to 'logical(1)'

logic1 || logic2
## Error in logic1 || logic2: 'length = 2' in coercion to 'logical(1)'

xor(logic1, logic2) # 排他的論理和
## [1]  TRUE FALSE

any(logic1) # 片方がTRUEなのでTRUE
## [1] TRUE

all(logic1) # すべてがTRUEでは無いのでFALSE
## [1] FALSE

論理演算子として、!(エクスクラメーションマーク、否定演算子)も用いることができます。!は論理型の前に置くことで、論理型を反転(TRUEFALSEに、FALSETRUEに)させます。

!による論理値の反転
!TRUE
## [1] FALSE
!FALSE
## [1] TRUE

!(1 < 3)
## [1] FALSE
!(1 > 3)
## [1] TRUE

4.5 条件分岐の文

上記のように、比較演算子や論理演算子を用いると、論理型を得ることができます。この論理型に従い、行う処理を変えるものを、条件分岐と呼びます。条件分岐では、条件分岐の文(Control structures)というものが用いられます。Rでは、条件分岐の文として、if文とswitch文の2つが設定されています。

表2:Rで使える条件分岐
条件分岐 条件分岐の形式
if文 if(条件式){TRUEのときの演算}else{FALSEのときの演算}
ifelse関数 ifelse(条件式, TRUEのときの演算, FALSEのときの演算)
switch文 switch(評価する値, 評価の既定値=既定値のときの演算)

4.5.1 if文

if文は最もシンプルな条件分岐の文です。if文では、条件式に従い、実行する処理が変わります。Rでのif文は、以下の形を取ります。

if(条件式){TRUEのときに実施する処理}

条件式をif()のカッコの中に書きます。if文は1行で書くこともできますし、複数行に渡って書くこともできます。複数行に処理を書くときには、中括弧({}を条件式の後に書き、中括弧の中に処理を書きます。

if文の使い方
if(TRUE) "Hello R" # 1行で書く場合("Hello R"が返ってくる)
## [1] "Hello R"

if(FALSE) "Hello FALSE" # 条件式がFALSEなので、何も返ってこない

if(TRUE){ # 複数行で書く時には中括弧({})を用いる
  "Hello R"
}
## [1] "Hello R"

if(FALSE){"Hello FALSE"} # 1行のif文で中括弧を使ってもよい

if文の条件が0のときには、0FALSEであると判断されて、処理が実行されません。一方で条件が0以外である場合には、TRUEであると判断されて処理が実行されます。if(0)とするとその処理が行われないので、Rではif(0)がコメントアウトに使われることもあります。

条件式が数値の時のif文
if(0){"0はFALSEなので、これは表示されません"}

if(-1){"-1はTRUE扱いなので、表示されます"}
## [1] "-1はTRUE扱いなので、表示されます"

if(-0.005){"0以外はTRUEとして処理されます"}
## [1] "0以外はTRUEとして処理されます"

4.5.1.1 if else文

if文ではさらに条件を分岐させることもできます。条件を追加する場合には、if文の後に、else if()を繋げます。else if()のカッコの中に2つ目の条件を書くことで、条件を分離させることができます。elseだけを書いて、if()の条件式をつけない場合には、どの条件にも合わない時に実行する処理になります。ですので、if else文は以下の形を取ります。

if(条件式1){
式1がTRUEのときの処理
}else if(条件式2){
式1がFALSE、式2がTRUEのときの処理
}else{
式1、2がFALSEのときの処理
}

if else文
x <- 2 # xは2

# xは2なので、2番目の処理が返ってくる
if(x == 1){ # =が1つだと代入になるのでエラーが出る
  "first"
} else if(x == 2){
  "second"
} else {
  "others"
}
## [1] "second"

4.5.1.2 ifelse関数

条件分岐が2つしかない場合には、ifelse関数を用いることもできます。ifelse関数は3つの引数、「(条件式)、(TRUEのときの処理)、(FALSEのときの処理)」を取ります。条件が1つだけで、簡単な処理のみを行うのであればifelse関数で十分な場合もあります。

ifelse関数
# TRUEなので2番目の処理が返ってくる
ifelse(1 < 3, "One is smaller than three.", "One is not smaller than three.")
## [1] "One is smaller than three."

# FALSEなので3番目の処理が返ってくる
ifelse(1 > 3, "One is larger than three.", "One is not larger than three.") 
## [1] "One is not larger than three."

4.5.2 switch文

条件式ではなく、特定の値に対応して処理を変えたい場合には、switch文を用います。switch文では、始めの引数が条件を指定する値、それに続く引数が条件に対応した処理となります。条件を指定する値には、数値または文字列を用いることができます。条件が数値の場合と文字列の場合では、やや使い方が異なります。

switch文(条件が数値のとき)
# 条件が1のときは、2番目の引数の処理が返ってくる
switch(1, "first", "second", "third") 
## [1] "first"

# 条件が2のときは、3番目の引数の処理が返ってくる
switch(2, "first", "second", "third") 
## [1] "second"

# 条件が5のときは、6番目の引数の処理がないので何も返ってこない
switch(5, "first", "second", "third") 
switch文(条件が文字列のとき)
# 条件式に対応したもの(=で繋いだもの)が返ってくる
switch("dog", dog = "犬", cat = "猫", monkey = "猿", pig = "豚")
## [1] "犬"

switch("monkey", dog = "犬", cat = "猫", monkey = "猿", pig = "豚")
## [1] "猿"

# horseは引数に登録していないので、何も返ってこない
switch("horse", dog = "犬", cat = "猫", monkey = "猿", pig = "豚")

インストールしたばかりのRでは、上記のif文、if else文、ifelse関数、switch文しか使えませんが、ライブラリというものを用いると、他の条件分岐(if_else関数やcase_which文、case_when文)などを用いることもできます。詳細については16章で説明します。