VBAと日々のこぼれ話

  1. VBA

【ExcelVBA】重複なしリストが作りたい

重複なしのリストを作成するには、

1.元のシートをコピーし別シートととする
2.データタブ > 重複の削除

正直コードを書かなくったってという身も蓋もない話はありますが、とある処理の一部分であったり、手作業によるヒューマンエラーを避けたいだとか自動化したいという場合はやはり自動化してあげるのが良いかと思います。

重複なしのリスト作成の自動化方法

ぱっと思いつく方法は、

①RemoveDuplicatsメソッドを使う
②Dictionaryオブジェクトを使う

※①はExcel2007から実装されたためそれ以前のバージョンでは使えません。

他にも一旦配列やコレクションに入れてループさせながら重複を除外するといった力技もありますが、対象のレコード数(セル数)が多ければ処理時間がかかる上に何よりコードが複雑になるのであまりお勧めはしません。
※コーディングの勉強にはなると思うので挑戦するのはありだと思います。

どちらを推奨するか

いつも言っているようにケースバイケースで使い分けてあげるのがよさそうです。

賢さで選ぶならRemoveDuplicatsメソッド

何が賢いかというと、範囲設定により複数列の組み合わせで重複を判定できるところです。

そう。Excelの「重複の削除」の機能と同じことが可能なのです。

バージョン問題さえ解決できていれば、非常に便利ですよ。

一方のDictionaryオブジェクトは、複数列の重複削除はできますがいくつも仕掛けを作らねばいけません。

汎用性を選ぶならDictionaryオブジェクト

何といってもExcel2003以前でも使える汎用性の高さと実績。

ExcelVBAのコードについて解説しているサイトでは、②が主流かなと思います。

バージョンのことを考えなくても良いというのは開発する際の大きなメリットですし、私も真っ先に思いつくくらい王道な方法です。

汎用性といえば、同一ソフト内のバージョンの差だけではありません。

ExcelVBAメインの方であればあまり関係ありませんが、AccessVBAにも携わる方なら②→①の優先順をお勧めします。

AccessVBAを触ったことある方ならもしかするともう感づいておられるかと思いますが、「RemoveDuplicatsメソッド」は、AccessVBAでは使えないからです。

ただAccessVBAで使えないというのは言い過ぎです。

正確に言うと、「RemoveDuplicatsメソッド」は、AccessVBAでExcelを操作する際には使えますがAccess内のデータベースには使えないが正しいです。

【スポンサーリンク】



理由は、単純明快。

Rangeオブジェクトのメソッドだからです。

ここで「Rangeオブジェクトのメソッドとは何か」という疑問を持たれる方も多いいと思います。

詳しく説明するのは長くなるのでざっくり説明すると、RangeオブジェクトとはExcelシートのセルや範囲指定されたセル群(行とか列含む)であり、そのオブジェクトに対するメソッド(機能)という意味になります。

要は、Rangeオブジェクトが存在しない(Excelシートのセルがない)Accessのデータベースでは使いようがないという訳です。

一方のDictionaryオブジェクトは、Excel/Access関係ないので応用が利きます。

これも②が主流派である理由かもしれません。

サンプルコードの前提

というわけで、今回は単一列の重複なしリストを作成するコードです。

アプローチが違うので、リストシートの作成が(シートの追加 or シートのコピー)という違いはありますが、①と②は最終的な結果は同じになります。

リスト化したいデータは、単一列
testシートのA列を重複なしのリストとしてリストシートへ書き出す
testシートの最終行が8行目(ヘッダー含む)とあらかじめ分かっているとみなす

①RemoveDuplicatsメソッドを使う

※Excel2007から実装されたためそれ以前のバージョンでは使えません。

ポイント Columnsの指定

重複をチェックする列の指定ですが、省略すると範囲内の全ての列が対象になります。
今回のように1行しかない今回は省略しても影響はありません。
今回は分かりやすいように記載しました。
もし複数列を指定する場合は、列のインデックス番号をArray関数で設定してください。

【スポンサーリンク】



②Dictionaryオブジェクトを使う

※keysの型宣言を間違えていました。正しくはVariantです。

ポイント① On Error Resume Next

通常、Dictionaryオブジェクト内に既に登録されているキーを重複して登録(.Add)しようとするとエラーが出ます。

ですので、登録する前に存在確認(Exists)の判定処理を入れます。

ですが今回は、重複データはばっさり切り捨てたい、何が重複しているのかも特に知りたくはない、なるべくすっきりさせたい。

そこで、登録時にエラーが出ようが無視するようにしています。こうすることで、重複がきてもエラーは出ない上に、Dictionaryオブジェクトにも登録されません。

注意したいのは「On Error Resume Next」以降の全てのエラーは無視されてしまうので、同一プロシージャ内に続けて処理を書きたい(かつエラーを検知したい)場合は要注意です。

解除する(On Error Goto 0)なり、プロシージャを分割する必要があります。

ポイント② リスト書き出し時のループ回数

Dictionaryオブジェクトに登録されている項目は8個(.Countで取得)ですが、Dictionaryオブジェクトのインデックス(添え字)は「0」から始まります。

つまり、今回はインデックス「0~7」となります。

またFor Nextステートメントループカウントは1(省略するとデフォルトで1となる)なので、ループ指定回数は、startが0、endは項目数 – 1となります。

【スポンサーリンク】



VBAの最近記事

  1. 【VBA】未だに苦手としていること

  2. 【VBA】モジュール先頭に記述する4種類のOption キーワード ステートメント

  3. 【VBA】同じ階層体系のフォルダを量産したい

  4. VBAの腕を知るための3つの短い質問を考える

  5. 【VBA】ExcelやテキストへDAO・ADO接続する際に使用するISAMフォーマット一覧…

関連記事

【スポンサーリンク】




PAGE TOP