7. 条件判断

今まで見てきたように、一般的にプログラムは書かれている順番に(上から下に)一行ずつ実行されていきます。
しかしこれでは、「特定の場合にのみ実行したい」、「この部分を繰り返して実行したい」といった場合に困ってしまいます。
そこで使われるのが「制御構造」と呼ばれる仕組みです。

条件判断

プログラムは基本的にコードを上の行から一文ずつ実行していきますが、「数値が10より小さい場合だけ処理したい」などの条件によってその後の処理を分けたい場合もあります。
条件判断を使用することで、以下のような場合分けが実現出来ます。

conditional_branch.rb
1
2
3
4
5
6
7
8
9
10
11
num = 2

if num < 10
  # 条件が真(true)のときの処理
  puts "nは10より小さい"
else
  # 条件が偽(false)のときの処理
  puts "nは10より大きい"
end

#=> nは10より小さい

比較演算子

真偽条件に使う演算子は次のようなものがあります。

比較演算子 trueとなる条件  
a == b a と bの値が等しい a == 100 a が 100 のとき true
a != b a と bの値が異なる a != 100 a が 100 以外のとき true
a < b a が bより小さい a < 100 a が 100より小さいとき true
a > b a が bより大きい a > 100 a が 100より大きいとき true
a <= b a が b以下 a <= 100 a が 100以下のとき true
a >= b a が b以上 a >= 100 a が 100以上のとき true

論理演算子

複数の条件を組み合わせたり、条件を反転させるときに使います。

論理演算子 意味 trueとなる条件
条件1 && 条件2 条件1 かつ 条件2 条件1条件2 がともに
条件1 || 条件2 条件1 または 条件2 条件1 または 条件2 のどちらかが
!条件 条件 でない 条件のとき
logical_operator.rb
1
2
3
4
5
6
7
8
9
num = 18

if 10 <= num && num < 100
  puts "#{num}は二桁の正の数です"
else
  puts "#{num}は二桁の正の数ではありません"
end

#=> 18は二桁の正の数です

条件文(if・unless)

条件によって処理を変える際には
「ある条件の時~したい」/「ある条件の時~したくない」というケースがあります。
前者の場合はif、後者の場合はunlessを用います。

まずは例を見てみましょう。
以下は、変数numに指定された数値が0の場合「numは0です」、数値が0以外の場合「numは0ではありません」と表示するものです。
numの値を変えて試してみましょう。

unless.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
num = 0

# 数値が0の場合「numは0です」と表示したい
if num == 0
  puts "numは0です"
end

# 数値が0でないとき「numは0ではありません」と表示したい
unless num == 0
  puts "numは0ではありません"
end

#=> numは0です

ifunlessは、読みやすさを重視して使い分けてください。
それぞれ詳しく見ていきましょう。

ある条件の時~したい: if

前述のとおり、主に「ある条件の時~したい」際に使用します。

1
2
3
if condition
  # 条件が真のときの処理
end

次の例は、数値が奇数か偶数かを判断して文字を出力します。

odd_or_even.rb
1
2
3
4
5
6
7
8
9
num = 20

if num % 2 == 0
  puts "偶数です。"  #=>numが偶数のとき
else
  puts "奇数です。"  #=>numが奇数のとき
end

#=> 偶数です

上記の例のように、
評価式がである場合(if)とである場合(else)とで処理を分けたい場合、以下のように記述します。

1
2
3
4
5
if condition # 条件
  # 条件が真であるときの処理
else
  # 条件が偽であるとき処理
end

また、複数の条件を段階的に設定したい場合は、elsifを使いましょう。

elsif.rb
1
2
3
4
5
6
7
8
9
10
11
num = 1

if num == 0
  puts "0です"  #=>numが0のとき
elsif num >= 1
  puts "正の数です" #=>numが1以上のとき
else
  puts "負の数です"  #=>numが0より小さいとき
end

#=> 正の数です

まとめるとこのようになります

1
2
3
4
5
6
7
8
9
if condition1 # 条件1
  # 条件1が真であるのときの処理
elsif condition2 # 条件2
  # 評価2が真であるのときの処理(条件1は偽)
elsif condition3 # 条件3
  # ...
else
  # 条件1,条件2,…が偽でないときの処理
end

ある条件でない時~したい: unless

unlessは、評価式がのとき処理を実行します。

1
2
3
unless condition # 条件
  # 条件が偽であるときの処理
end

ifで記述して読みづらいと感じたときは、unlessで書いてみることも考えてみてください。

if_vs_unless.rb
1
2
3
4
5
6
7
8
9
10
11
12
text = "hoge"

if !(text == "")
  puts "textは空文字ではありません"
end
#=> textは空文字ではありません

# すっきりする
unless text == ""
  puts "textは空文字ではありません"
end
#=> textは空文字ではありません

unlessにおけるelse以下の処理は、評価式が偽でないとき(=であるとき)に実行します。

1
2
3
4
5
unless condition # 条件
  # 条件が偽であるときの処理
else
  # 条件が偽でないときの処理 = 真であるときの処理
end

しかし、この書き方はあまり推奨されていません
unlessが「条件を満たさない場合」、elseが「条件を満たさない場合じゃない場合」という意味になり、とても分かりづらいからです。
この場合、if ~ else ~ endで置き換えましょう。
参考:コーディング規約
また、unless文はif文と異なり、elsifにあたるものはないので注意しましょう。

case文

ある1つの変数に対して、複数の候補値によって処理を分けたい場合、case文が有効です。

1
2
3
4
5
6
7
8
9
10
case var
when value1
  # varが値1のときの処理
when value2
  # varが値2のときの処理
when value3
  # varが値3のときの処理
else
  # どの値にも一致しないときの処理
end

例えば、以下のような、ifで書かれた条件判断があるとします。

1
2
3
4
5
6
7
8
9
10
11
12
13
num = 2

if num == 0
  puts "numは0です。"
elsif num == 1
  puts "numは1です。"
elsif num == 2
  puts "numは2です。"
else
  puts "numはどの条件にも当てはまりません。"
end

#=>numは2です。

numが何回も出てきて、見づらいですね。
1つのnumに対して、複数の候補(0,1,2,その他)から一致する条件を探しているパターンです。
上記のものを、case文に書き換えてみましょう。

case.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
num = 2

case num
when 0
  puts "numは0です。"
when 1
  puts "numは1です。"
when 2
  puts "numは2です。"
else
  puts "numはどの条件にも当てはまりません。"
end

#=>numは2です。

文字数も少なく、とてもすっきりしました。
「同じnumを評価している」ということがぱっと見で分かりやすいですね。

範囲式

case文のwhen句には、範囲を指定することも出来ます。

case_range.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
num = 2

case num
when 1..9
  puts "numは一桁の正の数です。"
when 10..99
  puts "numは二桁の正の数です。"
when 100..999
  puts "numは三桁の正の数です。"
else
  puts "numはどの条件にも当てはまりません。"
end

#=>numは一桁の正の数です。

真と偽

さて、ここまでに「」「」という記述とtruefalseという記述があったと思います。
一見するとこの二つは同じもののようですが、実はRubyにおける/の概念はtruefalseと一対一で結びついているわけではありません。
に該当するのはfalsenilの二つで、その他のオブジェクトはすべてとなります。

真偽 オブジェクト
falsenil除くすべて
falsenil
true_false.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
objects = [
  [],     # Arrayクラス
  {},     # Hashクラス
  "",     # Stringクラス
  0,      # Numericクラス
  true,   # Trueクラス
  false,  # Falseクラス
  nil     # Nilクラス
]

objects.each do |object|
  p object

  if object
    puts "=> 真"
  else
    puts "=> 偽"
  end
end

# []
# => 真
# {}
# => 真
# ""
# => 真
# 0
# => 真
# true
# => 真
# false
# => 偽
# nil
# => 偽

Step Up! : 式修飾子 (後置 if・unless)

if文やunless文を一行で記述する方法で、elseを必要としない場合に使用することが多いです。

1
2
process if condition
process unless condition

例:

suffix_if.rb
1
2
3
4
a = 0
b = 1
puts "aは0です。" if a == 0  #=> aは0です。
puts "bは0です。" if b == 0  #=> (表示されない)

Step Up! : 条件演算子(三項演算子)

if ... else ...の場合も一行で記述できる方法があります。

1
condition ? value_for_true : value_for_false

例:

1
2
3
4
a = 10
b = -5
puts a >= 0 ? a : -a  #=> 10
puts b >= 0 ? b : -b  #=> 5

三項演算子を用いることでシンプルに書ける場合は使ってみましょう。
ただし、複雑な分岐になるほど三項演算子は可読性が低くなってしまいますので注意が必要です。


演習問題

問1

指定した数値num3で割り切れるか判定し、以下のような出力をする条件分岐を作成して下さい。

1
2
3
4
5
num = 15
#=> 15は3で割り切れます

num = 7
#=> 7は3で割り切れません

問2

おにぎり(100円), お茶(150円), 弁当(500円)があります。
所持金moneyを入力したとき、その所持金で購入可能な商品の一覧を出力させてください。

1
2
3
4
5
6
7
8
9
10
# money = 200 の場合
#=> 購入可能な商品 : おにぎり, お茶

# money = 0 の場合
money = 0
#=> 購入可能な商品 :

# money = 500 の場合
money = 500
#=> 購入可能な商品 : おにぎり, お茶, 弁当

※いろいろな書き方が考えられます。時間があったら考えてみましょう。