今の会社に転職してからVBAで業務効率化を図る毎日を送っています。もともとはVBA全くわからないど素人だったのですが、4年ほど前に実務でぶつかった問題に取り組むうちにある程度書けるように。

先日、同僚にVBAを教える機会があり、「各項目の個数を数える」という処理をVBAで書いてみようとなりました。ぱっと思いつくだけで3つほど方法があったので、それぞれ整理しておきます。

①WorkSheetFunctionのCountIfを使う方法

今回実際に同僚に教えたのはこの方法。Forループが1個だけで書けるので、VBA初心者でも理解しやすいのがポイントです。

Sub CountItems()
    Dim ws As Worksheet
    Dim i As Long
    Dim lastRow As Long
    
    ws = ThisWorkbook.Sheets("Sheet1")
    lastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
    
    ' A列の項目リストに対してB列に個数を書き出す
    For i = 2 To lastRow
        ws.Cells(i, 2).Value = WorksheetFunction.CountIf(ws.Range("D:D"), ws.Cells(i, 1).Value)
    Next i
End Sub

Forループの入れ子をいきなりやれと言っても「はて?」となるので、まずはこの形から入るのがおすすめです。

②Forループの入れ子で数える方法

最初に思いついた方法はこれ。自分でコードを書くときはあまり使いませんが、実務でVBAをやっていればForの入れ子には必ず遭遇するので、そのうち教えたい方法です。

Sub CountItemsNested()
    Dim ws As Worksheet
    Dim i As Long, j As Long
    Dim lastRowList As Long, lastRowData As Long
    
    ws = ThisWorkbook.Sheets("Sheet1")
    lastRowList = ws.Cells(Rows.Count, 1).End(xlUp).Row
    lastRowData = ws.Cells(Rows.Count, 4).End(xlUp).Row
    
    ' 検索元リスト(A列)の各項目について
    For i = 2 To lastRowList
        ' 検索先データ(D列)をループして一致したらセルに1を足す
        For j = 2 To lastRowData
            If ws.Cells(j, 4).Value = ws.Cells(i, 1).Value Then
                ws.Cells(i, 2).Value = ws.Cells(i, 2).Value + 1
            End If
        Next j
    Next i
End Sub

検索元の最初から最後までループする中に、検索先のループを入れ子にして、一致したら1を足していく方法です。セルに直接足していく方式なら2変数でもいけます。

③Dictionaryを使う方法

普段自分で使うならこれ。最初は全く理解できなかった連想配列も、めちゃくちゃわかりやすいYouTube動画を見てからはほぼこれを使っています。

Sub CountItemsDict()
    Dim ws As Worksheet
    Dim dict As Object
    Dim i As Long, lastRow As Long
    Dim key As Variant
    
    ws = ThisWorkbook.Sheets("Sheet1")
    lastRow = ws.Cells(Rows.Count, 4).End(xlUp).Row
    
    Set dict = CreateObject("Scripting.Dictionary")
    
    ' D列のデータをDictionaryに集計
    For i = 2 To lastRow
        key = ws.Cells(i, 4).Value
        If dict.exists(key) Then
            dict(key) = dict(key) + 1
        Else
            dict.Add key, 1
        End If
    Next i
    
    ' 結果をA列・B列に書き出す
    i = 2
    For Each key In dict.Keys
        ws.Cells(i, 1).Value = key
        ws.Cells(i, 2).Value = dict(key)
        i = i + 1
    Next key
    
    Set dict = Nothing
End Sub

3つの方法の中では一番処理が速く、検索元のリストがなくても個数を数えられるのがポイント。KeyにItemに個数を格納する形です。ただし連想配列の概念を理解していないといきなりはきついので、初心者にはだいぶ先に教える内容です。

まとめ:どの方法を使うべきか

  • VBA初心者・入門:①WorkSheetFunction.CountIf
  • Forループの練習として:②Forの入れ子
  • 実務・処理速度重視:③Dictionary

最終的にはDictionaryが使えると応用が広がるので、慣れてきたら③を目指すのがおすすめです。

マイクロソフトエクセル2019 アイコン by Icons8