Excelで2つの表を比較したいというケースがよくある。
たとえば、以下のように表Aと表Bがあり、それぞれ片側にしかないIDを抽出したい。
このとき、IDは重複がなく、昇順に並んでいるものとする。
VLookupでやれば簡単だが、表の規模が大きく、頻繁に行う場合はマクロ化しておくと早い。
まず、動的配列に入れて、ふつうに比較してみたのがこちら。
Sub 表比較_通常版() '表のデータ範囲を二次元配列に格納 Dim 表A: 表A = Sheets(1).Range("B5:C13") Dim 表B: 表B = Sheets(1).Range("E5:F17") '表配列を比較 cntA = 1: cntB = 1 Do While cntA <= UBound(表A, 1) And cntB <= UBound(表B, 1) If 表A(cntA, 1) = 表B(cntB, 1) Then cntA = cntA + 1 cntB = cntB + 1 ElseIf 表A(cntA, 1) > 表B(cntB, 1) Then Debug.Print "表Bだけに存在 =>"; 表B(cntB, 1) cntB = cntB + 1 ElseIf 表A(cntA, 1) < 表B(cntB, 1) Then Debug.Print "表Aだけに存在 =>"; 表A(cntA, 1) cntA = cntA + 1 End If Loop '上記Loopの片側が終了してしまった場合の後処理 Do While cntA <= UBound(表A, 1) Debug.Print "表Aだけに存在 =>"; 表A(cntA, 1) cntA = cntA + 1 Loop Do While cntB <= UBound(表B, 1) Debug.Print "表Bだけに存在 =>"; 表B(cntB, 1) cntB = cntB + 1 Loop End Sub
実行するとイミディエイトウインドウに以下のように表示される。
表Bだけに存在 => 66 表Bだけに存在 => 69 表Aだけに存在 => 70 表Aだけに存在 => 72 表Bだけに存在 => 74 表Aだけに存在 => 76 表Bだけに存在 => 78 表Bだけに存在 => 81 表Bだけに存在 => 87 表Bだけに存在 => 88
表A、表Bそれぞれに対応する配列を作成し、cntA、cntBで比較対象行を指し示すしているのだが、いかんせん配列の扱いはごちゃごちゃして分かりづらい。
そこで、クラスモジュールを使ってこれを少しスッキリさせてみる。
クラスモジュールの名前は表としておく。
コードはこちら。
Dim Table As Variant Dim cnt As Long Dim 列 As Long Private Sub Class_Initialize() cnt = 1 End Sub Sub Init(セル範囲 As Range, キー列) Table = セル範囲 列 = キー列 End Sub Property Get Value() As Variant Value = Table(cnt, 列) End Property Function 範囲内() As Boolean 範囲内 = cnt <= UBound(Table) End Function Sub 進める() If cnt <= UBound(Table) Then cnt = cnt + 1 End Sub
このクラスモジュールには、表を格納するTable変数、現在行の値を返すValueプロパティ、行を進める「進める」プロシージャ、現在行が表の範囲内かどうかを返す「範囲内」関数といった機能を持たせている。
このクラスモジュール「表」を用いたコードがこちら。
Sub 表比較_オブジェクト版() Dim 表A As New 表: 表A.Init Sheets(1).Range("B5:C13"), 1 Dim 表B As New 表: 表B.Init Sheets(1).Range("E5:F17"), 1 Do While 表A.範囲内 And 表B.範囲内 If 表A.Value = 表B.Value Then 表A.進める 表B.進める ElseIf 表A.Value > 表B.Value Then Debug.Print "表Bだけに存在 =>"; 表B.Value 表B.進める ElseIf 表A.Value < 表B.Value Then Debug.Print "表Aだけに存在 =>"; 表A.Value 表A.進める End If Loop Do While 表A.範囲内 Debug.Print "表Aだけに存在 =>"; 表A.Value 表A.進める Loop Do While 表B.範囲内 Debug.Print "表Bだけに存在 =>"; 表B.Value 表B.進める Loop End Sub
まず表オブジェクトを作成し、Initプロシージャでセル範囲とキー列をセットする。
※キー列は読み込んだ表の左から何列目を比較に使用するかを表す値。
後は表の範囲内で値を比較してどちらを進めるかという処理になる。
わずらわしい二次元配列の範囲チェックやカウント変数の管理、値の位置管理などがオブジェクト内に隠蔽されたことで、本体コードはスッキリとシンプルにまとまっている。これがオブジェクト指向の強力さである。