【VBAリファレンス|実務向け】重複データのチェック2 - For Each…NextとFindメソッドを使った方法

スポンサーリンク

なぜこの手法が重要なのか

実務で大量のデータから「重複を除外したリスト」を作成する際、単純なループ処理(For…Nextのネスト)を使うと、データ量に比例して処理時間が指数関数的に増大し、Excelがフリーズしてしまうことがあります。今回紹介する「For Each…Next」と「Findメソッド」を組み合わせる手法は、検索範囲を限定的に制御することで、処理速度を劇的に向上させることができます。大量の顧客名簿や商品リストを扱う現場では必須のテクニックです。

基礎知識:Findメソッドとは

VBAにおけるFindメソッドは、ワークシート上の「検索」機能をコードから実行するものです。通常のループで全セルを一つずつ比較するよりも、Excel内部の検索エンジンを活用するため、圧倒的に高速に目的の値を見つけることができます。
また、For Each…Nextステートメントは、指定した範囲内の各セルを順番に処理するのに適しており、最終行の数を意識せずに簡潔なコードが書ける点がメリットです。

実装のポイント

今回のコードでは、以下のロジックで処理を行います。
1. B列(結果出力先)をクリアする。
2. A列の各セルを「For Each」で順に回す。
3. すでにB列に書き出したデータの中に、現在の値が存在するかをFindメソッドで検索する。
4. 検索結果が「Nothing(見つからない)」の場合のみ、B列の末尾に追加する。

サンプルプログラム

以下のコードを標準モジュールにコピーして実行してください。A列にデータがある状態で動作します。

Sub ExtractUniqueValues()
Dim ALastRow As Long, BLastRow As Long
Dim FoundCell As Range
Dim c As Range

‘ B列をリセットし、見出しを設定
Columns(“B”).ClearContents
Range(“B1”).Value = “重複なしリスト”

‘ A列の最終行を取得
ALastRow = Cells(Rows.Count, 1).End(xlUp).Row
BLastRow = 1

‘ A列の各セルに対してループ処理
For Each c In Range(“A2:A” & ALastRow)

Set FoundCell = Nothing

‘ B列にすでに値が存在するか検索
If BLastRow > 1 Then
Set FoundCell = Range(“B2”, Cells(BLastRow, 2)) _
.Find(What:=c.Value, LookIn:=xlValues, LookAt:=xlWhole)
End If

‘ 見つからなかった場合のみB列に追記
If FoundCell Is Nothing Then
BLastRow = BLastRow + 1
Cells(BLastRow, 2).Value = c.Value
End If
Next c

MsgBox “重複を除いたリストを作成しました。”
End Sub

応用と注意点

1. COUNTIFとの使い分け
コード後半で触れた通り、`WorksheetFunction.CountIf` を使う方法も非常に直感的です。コード量はCountIfの方が短くなりますが、データが数万件を超えるような極めて大きなデータセットでは、Findメソッドの方がパフォーマンスが良い傾向にあります。

2. 検索の精度(LookAt)
Findメソッド使用時、`LookAt:=xlWhole`(完全一致)を指定することが重要です。「あ」を検索して「あいう」がヒットしてしまうような「部分一致」の誤判定を防ぐために、必ず完全一致を指定する癖をつけましょう。

3. データ型の確認
検索対象の値が数値か文字列かによって、Findメソッドが反応しない場合があります。データ型が混在しているシートでは、あらかじめセルの表示形式を統一しておくか、検索値を文字列として扱うなどの工夫が必要です。

タイトルとURLをコピーしました