ElseIf)で 3 通り以上に分けられるIIf 関数と If 文の違いを説明できるElse で受け止められる第 5 章の 1 行の If では、条件が真のときに文を 1 つしか書けません。
複数の文を実行したい、3 通り以上に分けたい ── そのための形がブロック If 文です。
If <条件式1> Then
<ブロック1>
ElseIf <条件式2> Then
<ブロック2>
︙
ElseIf <条件式n-1> Then
<ブロックn-1>
Else
<ブロックn>
End If
いちばん大事な性質。
元資料は書式を示すだけですが、ここを押さえないと必ずつまずきます ──
ElseIf は上から順に調べ、最初に真になったところだけを実行して、あとは飛ばします。
つまり 2 番目の条件は「1 番目が偽だった」ことが前提になっています。
だから ElseIf x >= 70 と書くだけで、
「70 以上かつ 80 未満」の意味になるのです(上に x >= 80 があるため)。
点数を入力し、70〜100 点であれば背景を緑で "Good"、 50〜69 点であれば背景をシアンで "Fine"、 0〜49 点であれば背景を赤で "Bad" を表示しなさい。
Sub Macro1()
Dim ten As Integer
ten = Cells(1, 2).Value
If ten >= 70 Then
Cells(2, 2) = "Good"
Cells(2, 2).Interior.Color = RGB(198, 239, 206) ' 緑
ElseIf ten >= 50 Then
Cells(2, 2) = "Fine"
Cells(2, 2).Interior.Color = RGB(183, 230, 240) ' シアン
Else
Cells(2, 2) = "Bad"
Cells(2, 2).Interior.Color = RGB(255, 199, 206) ' 赤
End If
Cells(2, 1) = "判定"
End Sub
上限を書いていないことに注目してください。
「70〜100 点」なのに If ten >= 70 Then だけです。
100 点までしか来ないことが分かっていれば、これで足ります。
そして ElseIf ten >= 50 は、
すでに「70 未満」であることが確定しているので 50〜69 になります。
上のプログラムには問題があります。 B1 に 150 や −20 を入れて実行してみてください。
課題の条件は「0〜100 点」の範囲しか決めていないので、 それ以外の値が来ると間違った判定を、エラーも出さずに返します。 元資料 10 枚目が、まさにこの点を課題にしています。
このプログラムに、条件
・101 点以上の場合 ⇒ Error(赤)
・マイナスの場合 ⇒ Error(赤)
以上 2 つの条件を追加して書き直せ。
Sub Macro2()
Dim ten As Integer
ten = Cells(1, 2).Value
' 先に「ありえない値」をはじく
If ten > 100 Or ten < 0 Then
Cells(2, 2) = "Error"
Cells(2, 2).Interior.Color = RGB(255, 0, 0)
ElseIf ten >= 70 Then
Cells(2, 2) = "Good"
Cells(2, 2).Interior.Color = RGB(198, 239, 206)
ElseIf ten >= 50 Then
Cells(2, 2) = "Fine"
Cells(2, 2).Interior.Color = RGB(183, 230, 240)
Else
Cells(2, 2) = "Bad"
Cells(2, 2).Interior.Color = RGB(255, 199, 206)
End If
Cells(2, 1) = "判定"
Cells(4, 1) = "150 や -20 を入れて確かめてください"
End Sub
おかしな値のチェックは、いちばん先に書く。
これは分岐を書くときの定石です。
もし ten > 100 の判定を最後に置いたら、
150 は先に ten >= 70 に引っかかって "Good" になってしまいます ──
ElseIf は上から順なので、条件を書く順番が意味を持ちます。
実務では、この「入ってくる値が想定どおりか確かめる」処理を 入力の検証(バリデーション)と呼び、 プログラムの分量の何割かを占めます。 正常な場合を書くのは簡単で、異常な場合を数え上げるのが難しいのです。
IIf ( <条件式>, <式1>, <式2> )
<式1> は条件式が真の場合、<式2> は偽の場合の値。
[例] a = IIf( x >= 30, "1.タクシーに乗る。", "バスに乗る。")
名前は「Immediate If」(すぐその場で判定する If)から来ています。 If 文は「文」ですが、IIf は「関数」── つまり値を返します。 だから代入式の右側やセルへの代入の中に、そのまま書けます。
If 文 | IIf 関数 | |
|---|---|---|
| 正体 | 文(処理の流れを分ける) | 関数(値を返す) |
| 分けられる数 | 何通りでも(ElseIf) | 2 通りだけ |
| 中に複数の文 | 書ける | 書けない |
| 向いている場面 | 処理そのものを分けたいとき | 値を 2 択で選ぶだけのとき |
IIf には落とし穴があります。
関数なので、真の側と偽の側の両方が評価されます
(使われない側も計算されます)。
たとえば IIf(b <> 0, a / b, 0) と書くと、
b が 0 のときも a / b が計算されてエラーになります。
第 5 章 §4.4 の And・Or と同じ事情です。
割り算や関数呼び出しを IIf の中に入れるときは注意してください。
Sub Macro3()
Dim x As Integer
Dim ten As Integer
x = Cells(1, 2).Value
ten = Cells(3, 2).Value
' 2 択なら IIf のほうが短い
Cells(2, 1) = "手段"
Cells(2, 2) = IIf(x >= 30, "1.タクシーに乗る。", "バスに乗る。")
' 合否も 2 択
Cells(4, 1) = "合否"
Cells(4, 2) = IIf(ten >= 60, "合格", "不合格")
' 3 通り以上は IIf を重ねられるが、読みにくい(悪い例)
Cells(6, 1) = "IIf を重ねた例"
Cells(6, 2) = IIf(ten >= 70, "Good", IIf(ten >= 50, "Fine", "Bad"))
Cells(7, 1) = "↑ 読みにくい。3 通り以上は If 文か Select Case を使う"
End Sub
Select Case <評価式>
Case <式1>
<ブロック1>
Case <式2>
<ブロック2>
︙
Case Else
<ブロックn>
End Select
1 つの値を、いくつもの場合に振り分けるときの書き方です。
ElseIf と同じことができますが、
「何を見て分けているのか」が 1 行目にはっきり書かれるのが利点です。
Case の書き方は 4 通りあります。元資料は
Case <式> の形だけを示していますが、実際にはこれだけ書けます。
| 書き方 | 意味 |
|---|---|
Case 3 | 値が 3 のとき |
Case 3, 5, 7 | 3 か 5 か 7 のとき(コンマで並べる) |
Case 70 To 100 | 70 以上 100 以下のとき(範囲) |
Case Is >= 60 | 60 以上のとき(比較。Is が必要) |
Case Else | どれにも当てはまらないとき |
Sub Macro4()
Dim ten As Integer
Dim hantei As String
Dim iro As Long
ten = Cells(1, 2).Value
Select Case ten
Case Is > 100 ' 101 点以上
hantei = "Error": iro = RGB(255, 0, 0)
Case Is < 0 ' マイナス
hantei = "Error": iro = RGB(255, 0, 0)
Case 70 To 100
hantei = "Good": iro = RGB(198, 239, 206)
Case 50 To 69
hantei = "Fine": iro = RGB(183, 230, 240)
Case 0 To 49
hantei = "Bad": iro = RGB(255, 199, 206)
Case Else
hantei = "?": iro = RGB(217, 217, 217)
End Select
Cells(2, 1) = "判定"
Cells(2, 2) = hantei
Cells(2, 2).Interior.Color = iro
Cells(4, 1) = "範囲がそのまま書けるので、条件の抜けを見つけやすい"
End Sub
こちらの版は、範囲が目で見て確かめられます。
70 To 100、50 To 69、0 To 49 と並べば、
すき間や重なりがないかがひと目で分かります。
ElseIf ten >= 50 という書き方では「上限は上の条件で決まっている」と
頭の中で補わなければなりません。読む人の負担が違います。
| 向いている場合 | 例 | |
|---|---|---|
If 〜 ElseIf |
条件ごとに見る変数が違うとき/複雑な条件式 | If gakusei And nen <= 25 Then … ElseIf kane > 5000 Then |
Select Case |
1 つの値を場合分けするとき | 点数の判定、曜日、メニュー番号、都道府県コード |
ax2 + bx + c = 0 の解は
ここで √ の中身 D = b2 − 4ac を判別式といい、 この符号で解の様子が変わります ── 分岐の練習にうってつけの題材です。
| 判別式 D | 解 |
|---|---|
| D > 0 | 異なる 2 つの実数解 |
| D = 0 | 重解(1 つ) |
| D < 0 | 実数解なし(虚数解) |
元資料が扱っていない、もう 1 つの場合。 上の公式には a で割る操作が入っています。 つまり a = 0 のときは使えません(0 で割るエラーになります)。 そして a = 0 なら、それはもう 2 次方程式ではなく bx + c = 0 の 1 次方程式です。 さらに b も 0 なら、c = 0 かどうかで「すべての x」か「解なし」に分かれます。 「ありえない入力」をはじくのではなく、意味のある別の場合として扱う例です。
Sub Macro5()
Dim a As Double, b As Double, c As Double
Dim D As Double
Dim x1 As Double, x2 As Double
a = Cells(1, 2).Value
b = Cells(2, 2).Value
c = Cells(3, 2).Value
Cells(5, 1) = "式"
Cells(5, 2) = a & "x^2 + " & b & "x + " & c & " = 0"
If a = 0 Then
' 2 次方程式ではない
If b = 0 Then
If c = 0 Then
Cells(6, 1) = "すべての x が解"
Else
Cells(6, 1) = "解なし(0 = " & c & " は成り立たない)"
End If
Else
Cells(6, 1) = "1 次方程式です"
Cells(7, 1) = "x"
Cells(7, 2) = -c / b
End If
Else
D = b ^ 2 - 4 * a * c
Cells(6, 1) = "判別式 D"
Cells(6, 2) = D
If D > 0 Then
x1 = (-b + Sqr(D)) / (2 * a)
x2 = (-b - Sqr(D)) / (2 * a)
Cells(7, 1) = "異なる 2 つの実数解"
Cells(8, 1) = "x1": Cells(8, 2) = x1
Cells(9, 1) = "x2": Cells(9, 2) = x2
ElseIf D = 0 Then
x1 = -b / (2 * a)
Cells(7, 1) = "重解"
Cells(8, 1) = "x": Cells(8, 2) = x1
Else
Cells(7, 1) = "実数解なし(虚数解)"
Cells(8, 1) = "実部": Cells(8, 2) = -b / (2 * a)
Cells(9, 1) = "虚部 ±": Cells(9, 2) = Sqr(-D) / (2 * a)
End If
End If
End Sub
試す値の例。
a=1, b=-5, c=6 → 2 つの解(2 と 3)/
a=1, b=-2, c=1 → 重解(1)/
a=1, b=0, c=1 → 虚数解(±i)/
a=0, b=2, c=-4 → 1 次方程式(2)/
a=0, b=0, c=5 → 解なし/
a=0, b=0, c=0 → すべての x。
6 通りすべてを試してみてください。
分岐を書いたら、すべての枝を 1 度は通すのがテストの基本です。
D = 0 という比較は、実は危ないです。
第 3 章で扱ったとおり、小数は 2 進数で正確に表せないことがあります
(a = 0.1 のような値を入れると、
本来 0 になるはずの判別式が 0.0000000001 のような値になり、
重解のはずが「異なる 2 つの実数解」と判定されることがあります)。
実務では If Abs(D) < 0.000001 Then のように許容誤差つきで比べます。
上のプログラムで a=0.1, b=-0.6, c=0.9 を入れて試してみてください。
If 〜 ElseIf 〜 Else 〜 End If。複数の文を書けるElseIf は上から順に調べ、最初に真になった枝だけを実行する。
だから順番に意味があるIIf は関数で値を返す。2 択専用。両側が評価されるので割り算に注意Select Case は1 つの値を振り分ける。
To で範囲、, で並列、Is で比較= 0 比較は許容誤差でもとにしたのは「情報学入門(VBA)135-2019」全 19 枚です。
| 元資料 | この教材 | 種別 |
|---|---|---|
ElseIf が上から順に調べ、最初に真になった枝だけ実行するという
肝心の性質が書かれていない |
明示した。「70〜100 点」なのに上限を書かなくてよい理由がここにある | 不足 |
Select Case の Case が
Case <式> の形だけ |
Case 3, 5, 7/Case 70 To 100/
Case Is >= 60 の 4 通りを表にした | 不足 |
If 文と Select Case の使い分けの指針がない |
「条件ごとに見る変数が違う → If」「1 つの値を振り分ける → Select Case」として表にした | 不足 |
IIf は書式と例だけで、If 文との違い(文か関数か)に触れていない |
比較表を追加。さらに両側が評価される落とし穴(0 で割る危険)を明記 | 不足 |
IIf の例が資料 130(第 5 回)と 135(第 6 回)の両方にある。
しかも 130 では x = IIf(...)、135 では a = IIf(...) と
代入先の変数名が違う(同じ例のはずが不統一) |
この章に集約し、135 の a = IIf(...) を採った | 重複 |
| 2 次方程式の解で a = 0 の場合(0 で割る)に触れていない | 1 次方程式・解なし・すべての x を含めた6 通りの場合分けにした | 不足 |
判別式 D を = 0 で比較している |
小数では危ない(第 3 章の誤差)。許容誤差つきの比較を追記し、実例で試せるようにした | 不足 |
| 課題(101 点以上・マイナスを Error にする)の答えと考え方が資料にない | 「おかしな値のチェックは先に書く」という定石として示し、実行できる形で載せた | 不足 |
元資料で正しかったこと。
ブロック If の書式、IIf の書式と説明
(「条件式が真の場合は式1 を返し、偽の場合は式2 を返す」)、
Select Case の書式、点数判定の課題設定(緑 Good・シアン Fine・赤 Bad)、
そして「101 点以上とマイナスを追加して書き直せ」という課題の立て方
── いずれも適切です。とくに最後の課題は、条件の穴に気づかせるよい設計なので、
この章の中心に据えました。