VBAの勉強を始めてみた

色々試しています。

空白以外のセルを一瞬でカウントするには?(Tips-5)

VBAの勉強を始めて、これまでに学んだことや、思いついたアレやコレをメモっておきます。

 

今回は、VBAで、セルにデータが有るか無いか(または特定のデータが有るか無いか、でもいい)を調べて、そのデータ数をカウントする方法についてです。

まず、下のように、For Each ~Next を使って A1:Z1048576 の範囲にデータがいくつ存在しているかをカウントしてみようと思います。
セルが空白ではない場合に、cnt を +1 します。

Sub test1()

    For Each myRange In Range("A1:Z1048576")
        If myRange.Value <> "" Then
            cnt = cnt + 1
        End If
    Next myRange
    
End Sub

 

おっと、その前に、処理にどのくらい時間がかかったのかを調べるために、時間計測できる仕掛けを組み込んでおきましょう。

Sub test1()

    StartTime = Time

    For Each myRange In Range("A1:Z1048576")
        If myRange.Value <> "" Then
            cnt = cnt + 1
        End If
    Next myRange
    
    StopTime = Time
    MsgBox "処理にかかった時間は" & vbCrLf & Minute(StopTime - StartTime) _
    & "分" & Second(StopTime - StartTime) & "秒"
    
End Sub

 

さあ、これでかかった時間は・・・・・・、

f:id:kouten0430:20180616165838j:plain

1分58秒

・・・・・・結構、かかったね(@_@;)

 

次は、A1:Z1048576 の範囲を配列に代入してから、配列をループして調べる方法を試してみます。配列の中身が空白ではない場合に、cnt を +1 します。

Sub test2()

    StartTime = Time

    Tdim = Range("A1:Z1048576")
    
    For i = 1 To 1048576
        For j = 1 To 26
            If Tdim(i, j) <> "" Then
                cnt = cnt + 1
            End If
        Next j
    Next i
    
    StopTime = Time
    MsgBox "処理にかかった時間は" & vbCrLf & Minute(StopTime - StartTime) _
    & "分" & Second(StopTime - StartTime) & "秒"
    
End Sub

 

かかった時間は・・・・・・、

f:id:kouten0430:20180616170038j:plain

5秒

圧倒的に速くなりましたよ!

 

この結果から、配列へのアクセスが速いこと(言い換えればループの都度、セルへアクセスすることが時間のかかること)が分かります。
ループというのは掛け算であり、ループの中に入っている処理が少し重いだけで、ループ回数によってはとんでもない時間を要してしまうんですよね・・・・・・。

 

でも、セルにデータが有るか無いかを調べるのであれば、もっと速い方法がありますよね?

それは、ワークシート関数を利用することです。test1、test2と同じ処理をワークシート関数を使って、書き直してみましょう。
CountIfで、空白以外のセル数をカウントさせます。

Sub test3()

    StartTime = Time

    cnt = WorksheetFunction.CountIf(Range("A1:Z1048576"), "<>")
    
    StopTime = Time
    MsgBox "処理にかかった時間は" & vbCrLf & Minute(StopTime - StartTime) _
    & "分" & Second(StopTime - StartTime) & "秒"
    
End Sub

 

かかった時間は・・・・・・、

f:id:kouten0430:20180616170224j:plain

0秒

速い!しかも、コードがすっきりするというオマケつき。

 

test1~3について、それぞれにかかった時間をまとめると下のようになります。 

方法 時間
For Each ~Next で1セルずつ調べる 1分58秒
配列に格納してから調べる 5秒
ワークシート関数で調べる 0秒

 

こうやって見ると、ワークシート関数が圧倒的に速いんですよね。

いや、けして、ワークシート関数利用推進派の回し者ではありませんよ。

 

おまけ:
今回のコードでは、A1:Z1048576 のセル範囲を試験的に調べましたが、じゃあ、A1:XFD1048576 の範囲(要するにシート内のすべてのセル)だったらどのくらい時間がかかるの?ということで、補足しておきます。
私のPCスペックでは、test1のケースで、単純計算で20時間かかり、test2のケースでは、メモリ不足のためテストすることすらできません。
しかし、test3のワークシート関数であれば、なんと!それでも 0秒 で処理が完了してしまいます。普段、ワークシート関数を使う分には何の疑問も抱きませんが、こうやって他の方法と比較してみると、「どうやって処理してるの?」と不思議に思ったりもします。

 

次回は、ワークシート関数以外で、ループ処理をなるべく使わずに済む方法を模索したり、ループ処理をどうしても使わなければならない場面で、ループ回数の掛け算の被乗数側となる処理をできる限り軽くする方法などについて考えてみたいと思います(@_@;)