可変長配列(Dictionary等)の機能整理
- 1.各可変長配列の特徴と機能
- 1ー1.宣言とオブジェクト生成
- 1ー2.データの追加
- 1ー3.データの取り出し
- 1ー4.データの削除
- アプリ実例
- コード・機能比較表(Excel) ・・・このページの表をA4横にまとめたもの
連想配列と呼ばれるCollectionやDictionaryのような可変長配列について、下記のようなシリーズで説明していきます。
・可変長配列の機能整理 ←今回
・可変長配列を使った重複除外リスト(単列)
・可変長配列を使った重複除外リスト(複数列)
ここでは「Collection」「Dictionary」「ArrayList」「SortedList」の4オブジェクトを取り上げます。
この他にも、「HashList」というArrayListやSortedListの仲間のオブジェクトもあります。名前の通りKey値を数値に変換し、その数値が示すインデックス位置にデータを保管するというもののようです。しかし保管したデータをKey値以外で取り出す方法が不明(Index等で取り出す手段が分からない)なため、今回の説明からは省いています。
とは言っても、理論的にはデータの存在有無を確認するのが高速に思えるので、何か面白い使い方を思いついたら、また御紹介したいと思います。
1.各可変長配列の特徴と機能
各可変長配列の特徴を簡単に図1にまとめ、その後で機能ごとに比較をしていきます。Object | 特徴 |
---|---|
Collection | どんな値でも格納可能。ユニークなKeyをセットにして格納すると、そのKeyで取り出し可。 |
Dictionary | 値とKeyをセットで格納。格納時にKeyの重複をチェック可能で、Keyも値も単データ・全データの取り出し可。 |
ArrayList | 必要に応じてサイズを動的に拡大できる配列。並へ替えのメソッドも有り、値の単データ・全データの取り出し可。 |
SortedList | 値とKeyをセットで格納し、格納した時点でKeyにより自動的に並べ替えられる。Keyも値も単データの取り出し可。 |
1ー1.宣言とオブジェクト生成
オブジェクトを使用するには、まずオブジェクトを生成する必要があります。各オブジェクトの宣言・生成方法は図2のようになります。 なお生成するオブジェクトの変数名は、ここでは各オブジェクトの頭文字(「C」「D」「A」「S」)としています。項目 | Collection | Dictionary | ArrayList | SortedList | |
---|---|---|---|---|---|
事前 バイン ディング | 参照 | ー | Microsoft Scripting Runtime | mscorlib.dll | |
宣言 | Dim C As Collection | Dim D As Dictionary (Dim D As Scripting | Dim A As ArrayList | Dim S As SortedList | |
生成 | Set C = New Collection | Set D = New Dictionary (Set D = New Scripting | Set A = New ArrayList | Set S = New SortedList | |
実行時 バイン ディング | 宣言 | ー | Dim D As Object | Dim A As Object | Dim S As Object |
生成 | ー | Set D = CreateObject ("Scripting | Set A = CreateObject ("System | Set S = CreateObject ("System |
「Collection」オブジェクトは、標準状態(参照設定へのライブラリファイルの追加不要)で宣言・生成することで使用できるようになります。
「Dictionary」は、事前バインディング(=アーリーバインディング)時には参照設定(VBEのツール→参照設定)で、「Microsoft Scripting Runtime」のライブラリファイルを追加します。
実行時バインディング(=レイトバインディング)時には、CreateObject関数に「Scripting.Dictionary」を指定して、オブジェクト生成を行います。
なお、単に「Dictionary」となっている場所を「Scripting.Dictionary」としても、宣言・生成が可能です。
「ArrayList」と「SortedList」を使用するには、まず「.NET Framework 3.5」がインストールされている必要があります。インストールされていな場合に、例えば実行時バインディングでCreateObjectを実行すると「オートメーションエラー」が発生してしまいます。
「.NET Framework 3.5」をインストールするには、図3のように「Windowsの機能」で「.NET Framework 3.5(.Net 2.0および 3.0を含む)」を有効化しインストールします。
図3
Windows10と11では「Windowsの機能」に辿り着くルートが少し異なります。
Windows10の場合は図3の左側のように、「コントロールパネル」→「プログラムと機能①」→「Windowsの機能の有効化または無効化②」を選択するとダイアログが表示されます。ダイアログ一番上の「.NET Framework 3.5(.Net 2.0および 3.0を含む)」にレ点③をし、OKボタンをクリックすれば、ダウンロードが始まり機能が追加されます。
Windows11の場合は図3の右側のように、「設定」→「アプリ④」→「オプション機能⑤」→一番下の「Windowsのその他の機能⑥」を選択するとダイアログが表示されます。ダイアログ一番上の「.NET Framework 3.5(.Net 2.0および 3.0を含む)」にレ点⑦をした後はWindows10と同じです。
「ArrayList」「SortedList」で事前バインディングを行う場合は、参照設定で「mscorlib.dll」を選択します。もしリスト内に存在しない場合は「C:¥Windows¥Microsoft.NET¥Framework
実行時バインディングを行う場合は「System.Collections.ArrayList」「System.Collections.SortedList」をCreateObject関数で指定します。
なお宣言と生成を一緒に実行する方法として、例えば「Dim C As New Collection」と1行で宣言+実行をする手法も他サイトでは紹介されています。しかし、この方法を使うと「オブジェクトが実行されるたびに存在がチェックされ、無ければ作成」する動作となってしまいます。(Microsoftの解説ページ)
よって、オブジェクトをNothingで解除した後でもオブジェクトが使えてしまう(=使おうとした時にオブジェクトが再生成される)という不自然な動きになります。短くて良いのですが「使わない」方が良さそうです。
1ー2.データの追加
各可変長配列にデータを追加する時に必要なコードと要件は、図4の通りです。項目 | Collection | Dictionary | ArrayList | SortedList | |
---|---|---|---|---|---|
データ の追加 | 末尾へ | C.Add | D.Add D.Item | A.Add | S.Add S.Item |
位置指定 | C.Add | ー | A.Insert | ||
入力要否 | Key | 任意 | 必須 | ー | 必須 |
値 | 必須 | 必須 | 必須 | 必須 | |
重複可否 | Key | 不可 | 不可 | ー | 不可 |
値 | 可 | 可 | 可 | 可 | |
入力可能 データ型 | Key | String | 配列以外OK(※1) | ー | 文字列、数値、日付(※2) |
値 | 何でもOK(※3) | 何でもOK(※3) | 何でもOK(※3) | 何でもOK(※3) | |
データ型 の混在 | Key | 不可 | 可 | ー | 不可 |
値 | 可 | 可 | 可(※4) | 可 | |
値の修正 | 不可 | D.Item | A.Item | S.Item | |
存在 チェック | Key | 無 (On Error Resume Next を使用) | D.Exists | ー | S. S. |
値 | 無 | 無 | A. | S. | |
先頭Index | 1 | 0 | 0 | 0 |
※2:配列・Object・Null値も初回は入力可だが、並べ替え時に比較が出来ない為に2回目以降は入力できず
※3:文字列、数値、日付、配列、セル範囲等のObject、Null値
※4:但しSortメソッド使用時は、比較が成立するように「配列、Object、Null値以外の同じデータ型」にする必要あり
図4
「Collection」は「Keyの指定は任意」ですが、設定するのであればString型のみです。Keyですので、指定するのであれば当然ながら「Keyの重複は不可」です。
またCollectionには、Keyの存在を調べるものがありませんが、「Keyの重複は不可」ですので「重複しているとエラー」が発生します。そのエラーを使い「On Error Resume Next」でAddメソッドの「値追加→エラー」をスルーさせることで、「エラー停止することなく、Keyも重複しないCollectionオブジェクト」を作成することが可能です。
またAddメソッドでパラメータを指定せずに引数を渡す場合は、第一引数「Item」・第二引数「Key」であり、他の可変長配列とは異なります。インデックスが「1」から始まるのも他の可変長配列と異なります。
Collectionには、位置を指定して格納するためのパラメータ「Before」「After」があります。どちらかを指定可能で、両方省略した場合は「末尾に追加」ということになります。「C.Count値以内」の整数で、挿入位置を指定します。
「Dictionary」は、Collectionとは異なり「Keyと値(Item)」は必須です。またAddメソッドでパラメータを指定しない場合は「Key」「Item」の順序になります。
Keyには配列以外は指定できますが、Objectを使ってしまうと「存在チェックのExistsメソッドで調べても必ずFalseが戻る」ことになるため役に立ちません。また図5で示す個別データ取得も出来ませんが、「全データ取得のD.Keysメソッドでは、Objectもまとめて取得可」となるようです。KeyにObjectを使用する際には注意が必要です。
値の修正時には「D.Item
「ArrayList」にはKeyはありません。ほぼ配列と同じ形です。またArrayListにはSortメソッドが備わっており、メソッド実行のみで並べ替えが可能です。但し値に「比較が出来ない配列・オブジェクト・Null値」などを入れてしまうと並べ替えが出来ず、Sortメソッド時にエラーが発生してしまいますので注意が必要です。
また「Insertメソッド」を使用すれば、挿入位置を指定してデータ追加することが可能です。
「SortedList」は、格納した直後に並べ替えが実行されます。ですので並べ替えの基準となるKey値には、「文字列・数値・日付」のみが可能です。しかも比較ができるようにするために「同じデータ型」で揃える必要があります。
このSortedListも、Dictionaryと同様に「S.Item
なお「値」のパラメータには、CollectionとDictionaryでは「Item」を使用しますが、ArrayListとSortedListでは「Value」を使用します。
1ー3.データの取り出し
格納したデータを取り出す時に必要なコードは図5の通りです。項目 | Collection | Dictionary | ArrayList | SortedList | |
---|---|---|---|---|---|
要素数取得 | C.Count | D.Count | A.Count | S.Count | |
個別 データ 取得 | Key | 無 | D.Keys()(Index) | ー | S.GetKey |
値 | C.Item C.Item C(Index) C(Key) | D.Items()(Index) D.Item D(Key) | A.Item A(Index) | S. S. S. S(Key) | |
全データ 取得 | Key | 無 | D.Keys | ー | 無 |
値 | 無 | D.Items | A.toArray | 無 |
「Collection」では、Keyは補助的なものであるためか、Key値を取得する手段がありません。また、全ての値を一気に取り出すものも存在しませんので、For~NextやFor Each~Nextを使用することになります。
「Dictionary」では、インデックスで値を取り出す際は「D.Items()(Index)」とします。VBAでは「オブジェクトの集合体であるコレクションには『s』をつける」ので、「D.Items(Index)」でも良いような気もしますが、受け付けてくれません。「Items」はプロパティでは無くメソッドで、「全ての値を戻す」という機能だからのようです。
ですので一旦「D_All = D.Items」のように変数で全ての値を受け取れば、「D_All(Index)」で受け取れるようになります。キーを受け取る「Keys」も同じくメソッドのため、同じように記述する必要があります。
「ArrayList」は「toArrayメソッド」で「全ての値」が取得できます。複数の値が入っている場合は、配列の形で戻されます。なおAddで格納する値を一次元配列とした場合には、toArrayで戻される値は二次元配列では無く「配列のネスト」が戻ります。戻された配列のインデックスはゼロスタートとなっています。
「SortedList」には全ての値・キーを取得する存在しないので、For~Next使用することになります。格納されているデータは、Keyの昇順で並んでいますので、降順で並べたい時にはFor~Nextを「Step -1」で逆に回して取り出します。
1ー4.データの削除
格納したデータを削除する時に使用するコードは図6の通りです。項目 | Collection | Dictionary | ArrayList | SortedList | |
---|---|---|---|---|---|
個別 削除 | Index指定 | C. | D. | A. | S. |
Key指定 | C. | D. | ー | S. | |
値指定 | 無 | 無 | A. | 無 | |
全削除 | Set C = New Collection | D. | A.Clear | S.Clear |
インデックス番号、キー値で削除する項目を指定する方法は、どの可変長配列でもほぼ同じです。SortedListには「S.RemoveRange(Index,個数)」というメソッドもありますが、VBAでは使用できない様です。
なおArrayListでは、値を指定したRemoveメソッドが使用でき、「インデックスの先頭から探して、最初に見つかった値の要素のみを削除」するようです。もし、ある値を全て削除したい時には、For~Next等で要素数(A.Count)が減らなくなるまで繰り返し実行すると良さそうです。但し、値がセル範囲などのオブジェクトや配列などの場合は、見つけることが出来ない(?)ようで、削除されませんので注意が必要です。
また全てのデータを削除する際、Collectionでは対応するメソッドが無いので、オブジェクトを生成し直すしかないようです。
アプリ実例
「CSVファイルでデータを読み書きする月間予定表」「サンプリング周期が異なるデータの補間法」
「複数行1データの並び替え」
「データの重みを考慮したComboBox入力補助」
「先入先出の入出庫管理システム」
「DVD等の内容・保管場所等管理システム」
コード・機能比較表(its-019.xlsx) ・・・このページの表をA4横にまとめたものです。