和風スパゲティのレシピ

日本語でコーディングするExcelVBA

複数のOR条件分岐を簡潔に書く方法5選

例えばこういったデータから対象データを抽出して処理するとします。

やさい売上データ


この時、実務では「にんじん,じゃがいも,たまねぎ,なす のうちどれか」という、
複数の対象を固有で指定する状況にたまに出くわします。


この指定、とりあえずORを使って愚直に書くと、

If Cells(R, 8) = "にんじん" _
Or Cells(R, 8) = "じゃがいも" _
Or Cells(R, 8) = "たまねぎ" _
Or Cells(R, 8) = "なす" Then

こんな感じになりますよね。

これをよりきれいに、わかりやすく書く方法がないかを考察します。

IF/ORステートメント

まずは上記のIF/ORステートメントを使用したコードです。

If Cells(R, 8) = "にんじん" _
Or Cells(R, 8) = "じゃがいも" _
Or Cells(R, 8) = "たまねぎ" _
Or Cells(R, 8) = "なす" Then

ちゃんと「_」を使って改行さえしておけば、これはこれで分かりやすいですね。

これをひとつの目安にしたいので、10万回判定の時間を計測しておくと、
IF/ORステートメントでは0.781秒という結果になりました。


これをこのロジックのまま読みやすくする場合は、説明変数を使って

Dim 商品名 As String
商品名 = Cells(R, 8)

If 商品名 = "にんじん" _
Or 商品名 = "じゃがいも" _
Or 商品名 = "たまねぎ" _
Or 商品名 = "なす" Then

こう書くことが可能です。よりきれいになっていいですね。

セルへのアクセスを1/4にできているため、
実行時間も0.211秒と4倍速に近いスピードが出ます。


まずは一番基本のこのコードをおさえておき、
これを基準にほかの書き方を見ていきましょう。

Select Case ステートメント

Ifと双璧をなす分岐ステートメントSelect Caseを使って書いたコードがこちらです。

Select Case Cells(R, 8)
Case "にんじん", "じゃがいも", "たまねぎ", "なす"


Select Caseの「並列のOR条件をカンマで併記可」という特長が活きて、
非常にわかりやすくシンプルに書けていますね。

CaseがこれしかないのにSelect Caseというのは若干違和感もありますが笑


セルのアクセスも1回なため、処理時間も0.203秒と高速です。


書きやすく、読みやすいバランスのいいコードですので、
複数のOR条件分岐にはこのコードをレギュラーにしておくといいと思います。

Functionプロシージャ

ここで判定をFunctionにした場合のコードを紹介します。

' メインコード内
If Isカレーの具(Cells(R, 8)) Then
' 関数
Function Isカレーの具(商品名 As String) As Boolean
    Select Case 商品名
    Case "にんじん", "じゃがいも", "たまねぎ", "なす"
        Isカレーの具 = True
    End Select
End Function

メインコードが劇的に短く読みやすくなりました。

コードに意味を付けられるので、
今回の判定が「カレーの具」を対象としていたこと判明しましたね。


実行時間も0.234秒とほぼ変わりません。
これは「Functionを呼ぶ時間はほぼ無視してよい」ということを意味します。


こういった判定に専用のFunctionを用意することのメリットとしては、

  • 同一判定がたくさんあるときに使いまわしが簡単
  • あとで「グリーンピース」を追加することになっても改修がここ一か所

という2点が非常に強力です。


この「判定条件のFunction化」もとても便利なので覚えておきましょう。

カンマ区切りテキスト&Instr関数

続いて「カンマ区切りテキスト & Instr関数」を使う方法です。

If InStr("にんじん,じゃがいも,たまねぎ,なす", Cells(R, 8)) > 0 Then

 
条件文字列を繋げてひとつのテキストにしておき、
Instr関数でデータがテキスト内に含まれているか判定する

という手法を用いています。

カンマ区切りと言いましたが、別に文字は何でもかまいません。


実行時間は0.312秒と、Select Caseほどではないですが十分早いですね。


この方法もコードが1行でとても分かりやすいですが、
それ以上に大きなメリットが「条件文字列を定数で持っておける」という点です。


マクロの設計を

' マクロ先頭
Private Const カレー対象商品リスト = "にんじん,じゃがいも,たまねぎ,なす"
Sub カレーの具に使う野菜の売上を集計する()
' 実際に使用する部分
If InStr(カレー対象商品リスト, Cells(R, 8)) > 0 Then

こんな風にすることで、

  • マクロの先頭で条件仕様が確認できる
  • 使いまわしが容易
  • 対象の変更時に改修が容易

という恩恵を得ることができます。


さらに、この手法を扱う場合は副産物として、

Dim 対象商品
For Each 対象商品 In Split(カレー対象商品リスト, ",")

という対象を1つずつ処理するFor Each文も使用することができます。


この方法で対象のデータを指定しているときは、
Splitで簡単に一次元配列が手に入ることも覚えておきましょう。

Dictionary(連想配列)

最後にDcitionaryオブジェクトを用いる方法です。

Dictionaryをよく使用する方は、以下のコードも参考にしてみてください。

' マクロ冒頭(あるいは別のプロシージャにてグローバルDictionaryに)
Dim Dicカレーの具 As New Dictionary
Dicカレーの具.Add "にんじん", ""
Dicカレーの具.Add "じゃがいも", ""
Dicカレーの具.Add "たまねぎ", ""
Dicカレーの具.Add "なす", ""
' 実際に判定する部分
If Dicカレーの具.Exists(Cells(R, 8).Value) Then

 
このようにDictionaryのExistsメソッドを使用しても、
今回の判定を分かりやすく簡潔に書くことができます。

実行時間も0.215秒と、流石Dictionaryは高速ですね。


このためだけにDictionaryを作るほどかというと微妙なところですが、
例えばItemにデータ件数を入れておくなど他の目的もある場合は、
判定とデータが完全に連動するため一石二鳥の良いコードになります。

この方法も参考にしてみてください。

配列(Array)は微妙。。。

もうひとつ配列を用いたコード、と言いたいのですが、
残念ながらVBAには「配列内に該当要素があるか」を判定する機能がありません。

一応WorksheetFunction.Matchがあるにはありますが、
なかった時のエラー処理が面倒だし、コードも不要に長くなります。


前述の「カンマ区切りテキスト」方式を使っておけば、
Instrで判定はでき、Splitで配列も手に入ります。

それでは足りず、判定以外にデータも保持したいということであれば、
今度は上位互換のDictionaryを使えばいいということになります。


今回の複数のOR条件分岐を扱うには、
配列はイマイチと思っておいてください。



以上で複数のOR条件分岐を簡潔に書く方法の解説を終わります。

  • IF/ORステートメント
  • Select Case ステートメント
  • Functionプロシージャ
  • カンマ区切りテキスト&Instr関数
  • Dictionary(連想配列)

の5つの方法を紹介しました。


どれが一番良いということはなくどれも特長がありますので、
みなさんの好みや状況に合わせて使い分けてみてください。