#38 Select CaseステートメントとChoose関数の比較

結論
Choose関数では、最初の引数の値に関わらず2番目以降のすべての式が実行されるため、Select Caseステートメントに比べて処理時間がかかる。またその遅くなる度合いも、If〜Elseステートメントに対するIIf関数のもの以上である。
ただし、非常に回数の多い繰り返し処理をする場合にはIIf関数以上にパフォーマンスが落ちるが、1回当たりの処理時間に関してはほとんど無視できる程度である。

#37ではIf〜ElseステートメントとIIf関数について比較してみましたが、これとまったく同様の関係を持っているのがSelect CaseステートメントとChoose関数です。Select Caseステートメントでは、Selectの次に記述された変数などの値に応じて、それぞれのCase節のコードを実行します。そこには複数行のコードを書くこともできます。一方、Choose関数は、IIf関数に似て、最初の引数の値によって2番目以降の対応する引数を返すものです。


RetValue = Choose(Index, Choice1, Choice2, ...., Choice-n)


複数行の処理を実行させることはできませんし、条件となる値(Index)も1・2・3・・・・・というように、1から始まる連続した整数である必要がありますが、分岐処理内容によっては、Select Caseステートメントより非常にシンプルに処理を表現することができます。

これら2つの違いも基本的にはIf〜Elseステートメント/IIf関数と同じと考えられますが、ここではそれをテストコードで実際に確認してみたいと思います。


まずはじめに、次のようなテスト用コードを使って、Choose関数の内部動作を確認してみましょう。イミディエイトウィンドウからcasetest_1プロシージャを実行してみます。

Sub casetest_1()
'Choose関数の動作の仕組みの検証

  Dim a

  a = 1

  Select Case a
    Case 1
      dummy "Select Case その1"
    Case 2
      dummy "Select Case その2"
    Case 3
      dummy "Select Case その3"
  End Select


  a = Choose(a, dummy("Choose その1"), dummy("Choose その2"), dummy("Choose その3"))


End Sub


Function dummy(strText As String)

  Debug.Print strText

End Function


実行結果
実行後のイミディエイトウィンドウ

IIf関数と同様、Choose関数でも、「a = 1」であるにも関わらず、2番目以降の引数に指定されたプロシージャがすべて呼び出されていることが確認できます。


次に、ループによってSelect CaseステートメントとChoose関数を多数回実行し、その時間を比べてみることにします。

ここでは次のような2つのコードを用意しました。1つ目は単に変数に値を代入するもの、2つ目は関数呼び出しを含めて、少々複雑な演算を実行させています。

Sub casetest_2()
'単に値を代入する場合のSelect CaseとChooseの比較

  Dim ilngLoop As Long
  Dim lngTmp As Long
  Dim lngRet As Long

  ts_Watch "処理開始", True

  For ilngLoop = 1 To 9999999
    lngTmp = (ilngLoop Mod 5) + 1
    Select Case lngTmp
      Case 1
        lngRet = 11
      Case 2
        lngRet = 22
      Case 3
        lngRet = 33
      Case 4
        lngRet = 44
      Case 5
        lngRet = 55
    End Select
  Next ilngLoop

  ts_Watch "Select Case ステートメント"

  For ilngLoop = 1 To 9999999
    lngTmp = (ilngLoop Mod 5) + 1
    lngRet = Choose(lngTmp, 11, 22, 33, 44, 55)
  Next ilngLoop

  ts_Watch "Choose関数"

End Sub



Sub casetest_3()
'関数を呼び出す場合のSelect CaseとChooseの比較

  Dim ilngLoop As Long
  Dim lngTmp As Long
  Dim dblRet As Double

  ts_Watch "処理開始", True

  For ilngLoop = 1 To 9999999
    lngTmp = (ilngLoop Mod 5) + 1
    Select Case lngTmp
      Case 1
        dblRet = Sin(ilngLoop) / 2
      Case 2
        dblRet = Sin(ilngLoop) / 3
      Case 3
        dblRet = Sin(ilngLoop) / 4
      Case 4
        dblRet = Cos(ilngLoop)
      Case 5
        dblRet = Tan(ilngLoop)
    End Select
  Next ilngLoop

  ts_Watch "Select Case ステートメント"

  For ilngLoop = 1 To 9999999
    lngTmp = (ilngLoop Mod 5) + 1
    dblRet = Choose(lngTmp, _
                    Sin(ilngLoop) / 2, _
                    Sin(ilngLoop) / 3, _
                    Sin(ilngLoop) / 4, _
                    Cos(ilngLoop), _
                    Tan(ilngLoop))
  Next ilngLoop

  ts_Watch "Choose関数"

End Sub



それぞれの実行結果は次のとおりです。

単に値を代入する場合 関数を呼び出す場合
Select Caseステートメント 3.8 秒 5.7 秒
Choose関数 25.3 秒 38.3 秒
ご覧のように、やはりIIf関数と同様に、Choose関数はSelect Caseステートメントに比べてパフォーマンスが劣ることが分かります。特に、1つ目のコードでは、単に固定的な値を代入しているだけなのですが、IIf関数に比べて絶対量がかなり増えています。Choose関数の場合、ふつうはIIf関数と違って何個もの引数を指定することが多いと思いますが、その分の違いが大きく現れているのかもしれません。そして、2つ目のコードでは、約1千万回の処理をしているとはいえ、38秒という非常に大きな時間を要しています。2番目から6番目の引数のすべての演算式が実行されることから考えれば、Select Caseステートメントの少なくても5倍のコストがかかって当然ですが、それでも絶対値としてかなり大きな時間です。これらのことから、やはりChoose関数に関しても「繰り返し処理では多用しない方がよい」、「引数に関数やプロシージャが含まれるときはSelect Caseステートメントにした方がよい」ということがいえるでしょう。とはいえ、もちろん1回当たりの処理時間はμ秒のレベルなので、少ない回数であれば影響はないといってよいでしょう。
| Index | Prev | Next |

 

Copyright © T'sWare All rights reserved