Excelの機能を使うかVBAで処理するか

配列データの重複を削除する場合、大きく分けると2つの方法があります。

1つはVBAで配列のループを行い、重複の判定を行って配列の再構築を行う方法です。

この方法はDictionaryクラスを使って高速化する方法と、素直に配列のループで行う方法の2通りが考えられます。

もう1つはExcelの重複の削除機能を使う方法で、処理の実体はRangeオブジェクトのRemoveDuplicatesメソッドを使う方法です。

それぞれサンプルコードも含めて紹介します。

以下では3つのコードを紹介していますが、一番おすすめなのは最初に紹介するDictionaryクラスを使う方法です。

なお、いずれの方法も元の配列の順序は維持しておくようにします。

配列の順序の維持とは、例えば「3,1,2,3,1,1」の6つのデータの重複を除去した場合に「3,1,2」とするか、ソートも行って「1,2,3」のようにしてもいいか、という話ですが、ソートをしたいのであれば重複を除去したあとにすればいい話で、コーディングの作法としては単に除去だけを行う方が都合がいい場合が多いと思います。

配列ループ+重複判定での配列再構築方法

配列ループの方法はVBAだけで完結したい場合に考え付く方法だと思います。

配列の中で重複している値を削除するには、配列に格納されている値の中でどれが重複しているのかを検出する必要があります。

そのため、最低1回は配列に各要素に格納されている値がなんであるかを確認する必要があります。

その際に、既に格納済みの値かどうかを確認すれば、重複しているかどうかが判定できます。

この考え方をそのままコードにすると、配列の二重ループ方式になります。

ただその場合、配列の要素が多い場合に処理に時間が掛かる欠点があります。

それを改善したい場合はDictionaryクラスなどのハッシュの考え方を利用します。

以下では高速に処理できるDictionaryクラスを使う方法と、処理時間が掛かる二重ループの方法の両方を紹介します。

Dictionaryクラスを使う重複除去

Dictionaryクラスを使うためには事前にVBA画面のツールメニュー→参照設定を選び、参照設定ダイアログで「Microsoft Scripting Runtime」にチェックを付けおく必要があります。

Dictionaryクラスの詳細については「VBAのDictionaryの使い方(全メソッドとプロパティ網羅)」をご参照ください。

処理の概要は、引数の配列をループして、各ループの値がDictionaryクラスにあれば何もせず、なければDictionaryクラスと編集用の配列に格納しています。

Dictionaryクラスは重複の有無判定のみに使用します。

DictionaryクラスのKeysをそのまま配列として返すことも出来ますが、その場合配列の元の順序が維持されない恐れがあるため利用せず、編集用の配列を別途利用しています。

 

次のコードはのDeleteSameValue1関数を呼ぶテスト用の関数です。

配列に「3, 1, 2, 3, 1, 1」の6つのデータがあり、重複を除いて「3, 1, 2」で返してもらいます。

実行結果
3
1
2

参考:配列二重ループでの重複除去

以下は引数に渡された配列から重複を除く関数(DeleteSameValue2)です。

関数内部で編集用の配列を用意します。

元の配列をループして、編集用の配列に格納されていなければ格納し、格納済みであれば重複データとして除外します。

この方式の欠点として、コードの形式として2つの配列が親子関係の二重ループになるため、処理時間も引数の配列のサイズにある程度比例することになります。

また、DictionaryクラスのExistsメソッドに該当する存在チェック処理が必要になるためどうしてもコードが長くなります。

実行結果は上と同じ結果になるため省略します。

Excelの重複の削除機能を使う方法

Excelの重複の削除機能を使う場合、先にも書きましたが処理の実体はセルを扱うRangeオブジェクトのRemoveDuplicatesメソッドです。

重複の削除機能は、対象のセル範囲の中で重複があれば削除して再表示する、という動きになります。

そのため、除去する前のデータをワークシートのセルに設定しておくことが前提になります。

そのため制約事項として、シートの最大行数(Excel 2007以降は1048576行)を超えるデータ数の場合は扱えないことになるため、セルへのデータ貼り付け時にエラーになるため処理しないようにしています。

配列データを貼り付けるシートをどうやって用意するか、という問題がありますが、ここではワークブックに新規シートを追加して、処理が終わったら追加したシートを削除する、という処理にしています。

セルに値を入力することになるため、セルの表示形式によって値が変わらないように表示形式を「文字列」にしてから配列の値をセルに設定しています。

配列データをセルに設定後にRemoveDuplicatesメソッドを使って重複を除去します。

あとは、配列をRedimで重複除去後の要素数で再構築しなおして、セルの値を再度配列に設定しなおしています。

次のコードはDeleteSameValue3関数を呼び出すテスト用関数です。

実行結果
3
1
2