こんにちは、すーみんです。この春からエンジニアになった新米プログラマ、遂にQiita初投稿です![]()
 どうぞよろしくお願いしますm(*_ _)m
プロローグ:分岐1つで処理は早くなる
ある日、先輩とペアプロをしていた際に、私は下のようなコードを書いていました。
For i = 1 To cnt
	If arr(i) = hoge Then
		'なんかの処理
	End If
	
	If arr(i) = fuga Then
		'なんかの処理
	End If
Next i
 するとボクはこんなことを言われました。
「この書き方だと大規模データに弱くなるよ。」
そして先輩は次のコードを提示しました。
For i = 1 To cnt
	If arr(i) = hoge Then
		'なんかの処理
	ElseIf arr(i) = fuga Then
		'なんかの処理
	End If
Next i
 if文の連続より、ElseIfで連続するほうが「判定処理が少なくなる」。
そう、先輩は教えてくれました。
なるほど確かに、ちょっと考えればわかることです。しかし具体的にどれくらい変わるのでしょう。気になったので調べてみました。
じっけん!
環境は以下のとおりです。
| 項目 | |
|---|---|
| OS | Windows 10 64bit | 
| メモリ | 8GB | 
| CPU | intel Core i5-7500 第7世代 | 
| Excel | Office 365 (VBA 7.0) | 
ソースコード
 計測用に1000万個のデータを下記のソースを使ってCollectionに格納し、For Eachで1000万個のデータに対してそれぞれIf分岐を実施しています。
ソースコードは以下のとおりです。
'If - ElseIf 2分岐の場合
Sub Example1()
    Dim i As Long
    Dim arr As Collection
    Dim ifA As Long
    Dim ifB As Long
    Dim t As Double
    Dim item As Variant
    
    Set arr = New Collection
    
    For i = 1 To 10000000
        arr.Add (i Mod 3)
    Next i
       
    ifA = 0
    ifB = 0
    
    '計測対象
    t = Timer
    For Each item In arr
        '分岐A
        ifA = ifA + 1
        If item = 0 Then
            GoTo continue
        '分岐B
        ElseIf item = 1 Then
            ifB = ifB + 1
            GoTo continue
        End If
continue:
    Next
    
    Debug.Print ("処理時間:" & Timer - t & "秒")
    Debug.Print ("分岐A:" & ifA & "回")
    Debug.Print ("分岐B:" & ifB & "回")
    
End Sub
'If - ElseIf 3分岐の場合
'長くなるのでFor Each の中のみ
For Each item In arr
     '分岐A
     ifA = ifA + 1
     If item = 0 Then
         GoTo continue
      
     '分岐B
     ElseIf item = 1 Then
         ifB = ifB + 1
         GoTo continue
        
     '分岐C
     ElseIf item = 2 Then
         ifC = ifC + 1
         GoTo continue
     End If
continue:
Next
 
 また、If - If のElseを使わない方法を実行するため、For Eachの中は、それぞれ下記のように書き換えて使用しています。
'If - If 2分岐の場合
'分岐A
For Each item in arr
   ifA = ifA + 1
   If item = 0 Then
         GoTo continue
   End If        
'分岐B
   ifB = ifB + 1
   If item = 1 Then
         GoTo continue
   End If
continue:
Next
'If - If 3分岐の場合
 For Each item In arr
     '分岐A
     ifA = ifA + 1
     If item = 0 Then
         GoTo continue
     End If
        
     '分岐B
     ifB = ifB + 1
     If item = 1 Then
         GoTo continue
     End If
        
     '分岐C
     ifC = ifC + 1
     If item = 2 Then
         GoTo continue
     End If
continue:
Next
微妙にコードが違う気がしますが…気にしないでいきましょう()
計測結果
比較表
(処理時間は1000分の1秒で四捨五入しています)
| 分岐タイプ | 2分岐 | 3分岐 | 
|---|---|---|
| If - ElseIf | 0.578 sec. | 0.640 sec. | 
| If - If | 0.625 sec. | 0.714 sec. | 
出力結果
'2分岐
If - elseIf の場合
処理時間:0.578125秒
分岐A:10000000回
分岐B:3333334回
If - If の場合
処理時間:0.625秒
分岐A:10000000回
分岐B:6666667回
'3分岐
If - ElseIf の場合
処理時間:0.640625秒
分岐A:10000000回
分岐B:3333334回
分岐C:3333333回
If - If の場合
処理時間:0.71484375秒
分岐A:10000000回
分岐B:6666667回
分岐C:3333333回
 比較表を見ての通り、2分岐では両者に約0.05秒、3分岐では約0.07秒の差が確認できました。
 また、処理回数も出力結果から分かる通り、分岐Bを通った回数にも差があることが確認できます。約330万データの分岐を省略できた分、ElseIfを使用するほうが早かったように思われます。
まとめ
今回の例では330万データをただ分岐するだけでしたが、場合によってはここで入出力処理を行ったり、データベースにクエリを発行したり、とコストの高い処理を行うこともあるかもしれません。そうなると、ただ分岐するだけで0.07秒の差は大きくなるような気がします。
 可能な限り、分岐の数を少なく、ですね![]()
ご指摘等ございましたら、コメントください。よろしくお願いします。