分岐処理、速度ってどう変わる？

　こんにちは、すーみんです。この春からエンジニアになった新米プログラマ、遂にQiita初投稿です:beginner:
　どうぞよろしくお願いしますm(*_ _)m

#プロローグ：分岐1つで処理は早くなる

　ある日、先輩とペアプロをしていた際に、私は下のようなコードを書いていました。

```visualbasic
For i = 1 To cnt
	If arr(i) = hoge Then
		'なんかの処理
	End If
	
	If arr(i) = fuga Then
		'なんかの処理
	End If
Next i
```

　するとボクはこんなことを言われました。
「この書き方だと大規模データに弱くなるよ。」

そして先輩は次のコードを提示しました。

```visualbasic

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分岐を実施しています。

　ソースコードは以下のとおりです。

```visualbasic
'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
```


```visualbasic
'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`の中は、それぞれ下記のように書き換えて使用しています。


```visualbasic
'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
```

```visualbasic
'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秒の差は大きくなるような気がします。

　可能な限り、分岐の数を少なく、ですね:slight_smile:

---

ご指摘等ございましたら、コメントください。よろしくお願いします。