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

この時、実務では「にんじん,じゃがいも,たまねぎ,なす のうちどれか」という、
複数の対象を固有で指定する状況にたまに出くわします。
この指定、とりあえず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つの方法を紹介しました。
どれが一番良いということはなくどれも特長がありますので、
みなさんの好みや状況に合わせて使い分けてみてください。