重複しないユニークなリスト作成 ~Dictionary オブジェクト(連想配列)を使う2~ (Excel VBA)

前回ミッション「重複しないユニークなリスト作成 ~Dictionary オブジェクト(連想配列)を使う1~ (Excel VBA)」のつづきです。

ミッションのおさらい

今回のミッションは、A列のメニューリストの重複しないユニークなメニュー名を、セルM2以下に書き出すことです。

→→→

プロシージャ

Sub 重複の無いユニークなリスト作成()

    '【変数】
    '配列関連
    Dim ary_d As Variant    '取り込みデータ用配列
    Dim ary_key As Variant  '書き出しkeyデータ用配列
    Dim dic_d As Object     'Dictionaryオブジェクト
    
    'その他
    Dim d_ct As Long        '配列ary_d用カウンター
    
    Application.ScreenUpdating = False
    
    '■データを配列ary_dに取り込み
    ary_d = Range("A2:A11")
    
    '■Dictionaryオブジェクトの準備
    Set dic_d = CreateObject("Scripting.Dictionary")
    
    '■配列ary_dをdic_dに格納
    For d_ct = 1 To UBound(ary_d, 1)
    
        '指定したキーがまだ登録されていなければ登録する
        If dic_d.Exists(ary_d(d_ct, 1))=False Then
            dic_d.Add ary_d(d_ct, 1), ""    'キー:ary_d(d_ct, 1)、値:空欄
        End If
    Next d_ct
    
    '■dic_d→配列ary_keyに格納
    ary_key = dic_d.Keys
    
    '■配列ary_keyをワークシートに書き出し(行列入替)
    Range(Range("M2"), Cells(dic_d.Count + 1, 13)) = Application.WorksheetFunction.Transpose(ary_key)
    
    '■dictinaryオブジェクトの解放
    Set dic_d = Nothing
    
    Application.ScreenUpdating = True
    
End Sub

Dictionary オブジェクト(連想配列)を使用する準備

Dictionary オブジェクト(連想配列)を使用する際には、オブジェクト型の変数で宣言し、CreateObject関数を使ってDictionaryを使えるようにしておきます。

Dim dic_d As Object       'Dictionaryオブジェクト
Set dic_d = CreateObject(“Scripting.Dictionary”)

参考:Dictionary オブジェクト(連想配列) CreateObject関数を使う方法・ 参照設定を使う方法 違いを理解してエラー防止(Excel VBA)

キー(key)に値(item)を関連付ける方法

Dictionary オブジェクトにキー(key)を登録し、そのキー(key)値(item)を関連付けることで、キー(key)インデックス番号から値(item)を呼び出すことができるようになります。

キー(key)に値(item)を関連付ける方法は、Addメソッドを利用する方法、Itemプロパティを利用する方法の2つあります。

Addメソッドを利用する方法

メソッド説明
Add key, item新しいキー(key)を登録し、値(item)を関連付けます。
(キーが既に存在する場合はエラーになります。)
Dictionaryオブジェクト.Add キー, 

↑Dictionary オブジェクトに キー(key)を登録し、そのキー(key)値(item)を関連付けます。

今回はDictinary オブジェクト「dic_d」に キー「ary_d(d_ct, 1)」を登録します。今回使用するのは、キー(key)のみなので、値(item)は関連付けず空欄 ”” としています。

dic_d.Add ary_d(d_ct, 1), ""

Dictinary オブジェクトdic_d」のインデックス番号は「0」から始まります。

Itemプロパティを利用する方法

プロパティ説明
Item(key)【キー(key)が登録されている場合】
・キー(key)に関連付けられた値(item)を取得します。
・「Dictionaryオブジェクト.Item(key) =別の値」で、既存の値(item)を別の値に変更します。
【キー(key)が登録されていない場合】
新しいキー(key)を登録し、値(item)を関連付けます。
(キーが既に存在する場合でもエラーになりません。)
いずれの場合も、「item」は省略可能。

Itemプロパティには、上記の通り色々な働きがあります。

キー(key)が登録されていない場合、新しい(key)を登録し、値(item)を関連付けます。

キー(key)が登録されている場合、既存値(item)が別の新しい値に上書きされます。

ですので、登録済のキーが存在する場合でもエラーが出ません。Existsの処理が不要になります。

値(item)を関連付ける必要がある場合は、既存値(item)が上書きされることを考慮して使用しなければいけません。

↓Itemを省略しない場合

Dictionaryオブジェクト.item(キー)= 

↓Itemを省略する場合

Dictionaryオブジェクト(キー)= 

Itemプロパティを使用するとExistsを使用せず、このような書き方でもOKです。少しだけコードがスッキリします。(itemは省略しています。)

'■配列ary_dをdic_dに格納
For d_ct = 1 To UBound(ary_d, 1)
   ’キーを登録する
    dic_d(ary_d(d_ct, 1)) = ""    'キー:ary_d(d_ct, 1)、値:空欄
Next d_ct

キー(key)にRangeオブジェクトが登録されないための「.value」の必要性

今回のコードでは、キー(key)に指定する値を配列から指定していますが、セルの値を指定する場合は「.value」を付けなければいけません。

dic_d.Add Cells(d_ct, 1).value, ""

Dictionary オブジェクトの引数キー(key)には数値や値だけではなく、オブジェクトを指定することも可能なのです.Valueを省略してしまうと、Rangeオブジェクトがキー(key)として登録されてしまいます。

「きつねうどん」の入っているセルA2、A4、A8、A10のRangeオブジェクトが別々のキー(key)と判断され、4つのセルの「きつねうどん」がキー(key)に登録されてしまいます。

セルの値をDictionary オブジェクトのキーに使用する際には「.value」を必ずつけなければいけません。

■■■スポンサーリンク■■■

指定したキーの存在確認

Dictionary オブジェクトのAddメソッドを実行する際、既に同じkeyが登録してあると、

実行時エラー’457′:
このキーは既にこのコレクションの要素に割り当てられています。

というエラーが出てしまいます。

そのエラーを回避するために、Existsメソッドを使用して登録済のkeyを処理しないようにしておきます。

メソッド説明
Exists(key)指定したキー(key)が存在するかどうか、論理値(True/False)を返します。
Dictionaryオブジェクト.Exists(キー)

↑Dictionary オブジェクトにキー(key)が既に登録されていたら「True」を返し、登録されていなかったら「False」を返します。

今回は キー「ary_d(d_ct, 1)が dictinary オブジェクト「dic_d」に登録されていない(False)場合、If 内の処理を行うようにしています。

If dic_d.Exists(ary_d(d_ct, 1)) =False Then
    dic_d.Add ary_d(d_ct, 1), ""
end if

Dictionary オブジェクト(連想配列)のキー(key)を一気に配列ary_keyに格納する

Dictionary オブジェクトのキー(key)を一気に配列に格納するにはKeysメソッドを使用します。

メソッド説明
KeysDictionaryオブジェクトのキー(key)を配列にして返します。
※配列のインデックス番号は0(ゼロ)から始まります。
配列=Dictionaryオブジェクト.keys

↑Dictionary オブジェクトの キー(key)全てを、配列として格納します。

今回は配列「ary_key」に、Dictionary オブジェクトに登録したキー(key)全体を配列として格納します。

ary_key = dic_d.Keys

この時の配列ary_keyのインデックス番号(添え字)は、「0」から始まります。

配列ary_keyをワークシートに行列を入れ替えて書き出し

上記説明でわかりやすくするために、配列ary_keyを縦並びに表現しましたが、配列ary_keyは1次元配列なので横並びになっています。

セルに書き出す際には、行列(縦横)を入れ替えてから書き出す必要があります。

セル範囲=Application.WorksheetFunction.Transpose(配列)

WorksheetFunction.Transposeメソッドで、横並びになっている一次元配列を縦並びにしてセル範囲に書き出します。

Range(Range("M2"), Cells(dic_d.Count + 1, 13)) = Application.WorksheetFunction.Transpose(ary_key)

参考

Dictionary オブジェクト(連想配列) とは ビッグデータ高速処理を可能にする技 (Excel VBA)
重複しないユニークなリスト作成 ~Dictionaryオブジェクト(連想配列)を使う1~ (Excel VBA)
重複しないユニークなリスト作成 ~Dictionaryオブジェクト(連想配列)を使う2~ (Excel VBA)
Dictionaryオブジェクト(連想配列) CreateObject関数を使う方法・ 参照設定を使う方法 違いを理解してエラー防止(Excel VBA)
Dictionary オブジェクト(連想配列)に登録されたキー(key)をまとめて取得する(Excel VBA)
Dictionary オブジェクトに新しくキー(key)を登録し、値(item)を関連付ける(Excel VBA)
Dictionary オブジェクト 実行時エラー 457 を出さないために 指定したキー(key)が登録されているか確認する(Excel VBA)
Dictionary オブジェクト(連想配列)に登録されたキー(key)をインデックス番号から取得(Excel VBA)
Dictionary オブジェクト(連想配列)に登録されたキー(key)を変更する(Excel VBA)
Dictionary オブジェクト(連想配列)に登録された値(item)をまとめて取得する(Excel VBA)
Dictionary オブジェクト(連想配列)に登録された値(item)を、キー(key)やインデックス番号を指定して取得する(Excel VBA)
Dictionary オブジェクト(連想配列)に登録された値(item)を変更する(Excel VBA)
Dictionary オブジェクト(連想配列)に登録されたキー(key)と値(item)を削除(Excel VBA)
Dictionary オブジェクト(連想配列)に登録されたキー(key)を一気に取得する(Excel VBA)
セル範囲を一気に変数(配列)に入れる ~バリアント型(Variant)変数を配列として使用する~(Excel VBA)

■■■スポンサーリンク■■■