皆様こんにちは、ノグチです。
前回までは、Dictionaryオブジェクトを使って、複数ループで書かれた重複排除の処理を
置き換えていく方法をご紹介してきました。
今回は、置き換え前の複数ループ文で書かれたコードと、Dictionaryに置き換えられたコード、どちらが処理速度が速いのか?を試してみたいと思います!
前回記事は、下記リンクをご覧ください。
追記:前回の記事に、「複数ループ側のコード内は、Dictionaryを使ったコードよりもシートアクセス回数が多いので、その分処理時間が長くなっているのでは」というコメントをいただきました。
コメントに沿ってコードを見直し、記事を修正しています。
処理時間比較用のリストとコード
検証用のリストデータ
このリストは前回までの記事で何度か登場してきましたが、今回はこの左側リストのレコード件数を10万件に増やして、各コードの処理時間を計測してみたいと思います!
複数ループを使った重複排除処理のコード
まず、ループを複数使って書かれた重複排除処理のコードがこちら。
先にお見せしたリストの、左側のリストにある品目の値が右側の出力リストにあるかどうかをループで探し、対象の品目が右側のリストにあった場合は在庫数を加算する、という動作のコードです。
Sub TestList() Dim i As Long Dim j As Long Dim flgFind As Long Dim maxRow As Long Dim maxRow_l As Long Dim strMat, lngNum Dim Start, Finish Application.ScreenUpdating = False Start = Time With ActiveSheet maxRow = .Cells(Rows.Count, 2).End(xlUp).Row maxRow_l = 1 For i = 2 To maxRow flgFind = 0 For j = 1 To maxRow_l strMat = .Cells(i, 2).Value lngNum = .Cells(i, 3).Value If strMat = .Cells(j, 6).Value Then .Cells(j, 7).Value = .Cells(j, 7).Value + lngNum flgFind = 1 Exit For End If Next j If flgFind = 0 Then .Cells(j, 6).Value = strMat .Cells(j, 7).Value = lngNum maxRow_l = maxRow_l + 1 End If Next i End With Finish = Time Application.ScreenUpdating = True MsgBox "処理時間は" & Format(Finish - Start, "nn分ss秒") & "です" End Sub
コードは前回の記事のものと全く同じですが、今回は処理時間の計測ということで、処理完了時にメッセージボックスで処理時間を表示するようにしました。
ついでに、画面の更新処理を非表示にするApplication.ScreenUpdating = Falseも加えてあります。
処理時間を計測する方法については、下記記事をご覧くださいね。
Dictionaryを使った重複排除処理のコード
そして、Dictionaryオブジェクトを使った重複排除のコードです。
こちらも、前回出てきたコードに処理時間を計測して、メッセージボックスで表示するコードと、画面更新非表示のコードを追加してあります。
Sub ListWithDictionary() Dim i As Long Dim j As Long Dim maxRow As Long Dim dic As Dictionary Dim strMat, lngNum Dim Start As Variant Dim Finish As Variant Application.ScreenUpdating = False Start = Time Set dic = New Dictionary j = 2 'リスト書き出し開始行 With ActiveSheet maxRow = .Cells(Rows.Count, 2).End(xlUp).Row For i = 2 To maxRow strMat = .Cells(i, 2).Value lngNum = .Cells(i, 3).Value If dic.Exists(strMat) Then .Cells(dic.Item(strMat), 7).Value = .Cells(dic.Item(strMat), 7).Value + lngNum Else dic.Add (.Cells(i, 2).Value), j .Cells(j, 6).Value = strMat .Cells(j, 7).Value = lngNum j = j + 1 End If Next i End With Finish = Time Application.ScreenUpdating = True MsgBox "処理時間は" & Format(Finish - Start, "nn分ss秒") & "です" End Sub
計測方法
前述2種類のコードを、冒頭にお見せした10万件のデータを使って実行時間を計測してみましょう。
計測時間の比較は、単純に各コードを3回ずつ実行して、平均した値で行っていきます。
実行結果
3回の平均は約11.3秒でした。
お次はDictionaryオブジェクトのコードを実行してみます。
平均を出すまでもなく結果が見えている気がしますが、先のコードの実行時間と比較すると若干スピードアップです。
各コードの処理時間を表にまとめてみました。
処理時間(秒) | 複数ループ | Dictionary |
---|---|---|
1回目 | 12 | 6 |
2回目 | 11 | 5 |
3回目 | 11 | 6 |
結果は、表のとおりDictionaryオブジェクトのコードが複数ループ文におよそ2倍ほどの差をつけて勝利でした。
Dictionaryオブジェクトを使ったコードの方が、ループが少ない分シートへのアクセス数が減って、処理時間が短くなっていそうです。
今回は処理対象の項目が2項目のみと少ないのでこの結果になっていますが、項目や処理の種類が増えるほど処理時間の差が開きそうですね。
最後に
今回は、Dictionaryオブジェクトを使って書かれたコードと、複数ループを使って書かれたコードの処理時間を比較してみました。
結果で見られた通り、Dictionaryオブジェクトを使ったコードならば高速化が見込めそうですね。
もし皆様のお手元にあるVBAコードの処理時間が長い、と悩んでおられるなら、Dictionaryオブジェクトでコードを書き換えてみてはいかがでしょうか。
次回は、Dictionaryオブジェクトに格納したキーと要素を、Dictionaryオブジェクトから直接ワークシートへ書き出す方法をご紹介します。
それでは、最後までお読みいただきありがとうございました!
連載目次:エクセルVBAのDictionaryオブジェクトでリストの重複を排除する
エクセルVBAでリストの重複を排除する方法として、Dictionaryオブジェクトを使った重複排除の方法をご紹介しています。