忍者ブログ

VB.NET-TIPS などプログラミングについて

VB.NETのTIPS(小技集)を中心に、Javascript、PHP その他のプログラミングについて少し役に立つ情報を発信します。いわゆる個人的な忘備録ですが、みなさんのお役に立てれば幸いです。

コレクション「Dictionary」の使い方について

コレクションクラスの中に Dictionary がありますが、以前の記事の List とは異なり、各要素にキー(索引)を持ちます。 そのキーを用いて要素にアクセスする連想配列の様なものです。 Dictionary クラスの定義は以下の様になっています。

■Dictionaryの宣言
Public Class Dictionary(Of TKey, TValue)
概要:
キーと値のコレクションを表します。
型パラメーター:
 TKey  : ディクショナリ内のキーの型。
 TValue: ディクショナリ内の値の型。


それでは Dictionary の使い方について順を追って説明したいと思います。


■簡単な Dictionary の宣言と使い方

以下のソースを見て下さい。
最初に Dictionary を生成し Add メソッドで新しく要素をキーと共に、3個追加します。 その後、追加したキーで要素を取得します。 尚、キーの指定で追加していないキーでの要素の取得を試みます。 (最後の取得でエラーが発生するはずです)

Public Class frmDictionary

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        ' Dictionaryの生成
        Dim dic As New Dictionary(Of String, String)
        ' 要素の追加
        dic.Add("A", "America")
        dic.Add("C", "China")
        dic.Add("J", "Japan")
        ' 要素の取得(KEY="A")
        Console.WriteLine("KEY:{0} のDictionaryの要素:{1}", "A", dic.Item("A"))
        ' 要素の取得(KEY="J")
        Console.WriteLine("KEY:{0} のDictionaryの要素:{1}", "J", dic.Item("J"))
        ' 要素に存在しないKEYの指定
        Console.WriteLine("KEY:{0} のDictionaryの要素:{1}", "X", dic.Item("X"))
    End Sub
End Class

実行結果としてコンソールには以下様に表示されますが、最後の取得で下図の様にエラーが発生します。

KEY:A のDictionaryの要素:America
KEY:J のDictionaryの要素:Japan


Dictionary の繰り返し処理は For Each で行う

上記のソースでは Dictionary の要素を Item プロパティで取得しましたが、 For Each 文を使えば Dictionary の要素を順次取得できます。 そこで上記のソースを以下の様に変更し実行してみます。

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        ' Dictionaryの生成
        Dim dic As New Dictionary(Of String, String)
        ' 要素の追加
        dic.Add("A", "America")
        dic.Add("C", "China")
        dic.Add("J", "Japan")
        ' For Each での順次処理
        For Each item In dic
            ' 要素
            Console.WriteLine("KEY:{0} のDictionaryの要素:{1}", item.Key, item.Value)
        Next
    End Sub

結果は以下の様になります。ここで For Eachitem 変数なのですが、これは KeyValuePair 型になります。 これ自身は Structure なのでそのプロパティにアクセスしてキー(Key)と値(Value)を取得します。

KEY:A のDictionaryの要素:America
KEY:C のDictionaryの要素:China
KEY:J のDictionaryの要素:Japan

ここで KeyValuePair 型についてですが、VBでの内部では以下の様に宣言されています。

■KeyValuePairの宣言(一般的な宣言)
Public Structure KeyValuePair(Of TKey, TValue)

この宣言は一般的なものであり、それぞれの Dictionary によって TKeyTValue の部分のデータ型が変わります。

■今回の例のKeyValuePairの宣言について
Public Structure KeyValuePair(Of String, String)

依って、上記のソースの9行目は厳格に宣言するのであれば以下の様にします。

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        ' Dictionaryの生成
        Dim dic As New Dictionary(Of String, String)
        ' 要素の追加
        dic.Add("A", "America")
        dic.Add("C", "China")
        dic.Add("J", "Japan")
        ' For Each での順次処理
        For Each item As KeyValuePair(Of String, String) In dic
            ' 要素
            Console.WriteLine("KEY:{0} のDictionaryの要素:{1}", item.Key, item.Value)
        Next
    End Sub



Dictionary にはキー及び値のみのコレクションを持っていますので、それぞれを別々に For Each 処理できます。

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        ' Dictionaryの生成
        Dim dic As New Dictionary(Of String, String)
        ' 要素の追加
        dic.Add("A", "America")
        dic.Add("C", "China")
        dic.Add("J", "Japan")
        ' For Each でのキーの順次処理
        For Each strKey As String In dic.Keys
            ' 要素
            Console.WriteLine("KEY:{0}", strKey)
        Next
        ' For Each での値の順次処理
        For Each strVal As String In dic.Values
            ' 要素
            Console.WriteLine("Dictionaryの要素:{0}", strVal)
        Next
    End Sub

結果は以下の様になります。

KEY:A
KEY:C
KEY:J
Dictionaryの要素:America
Dictionaryの要素:China
Dictionaryの要素:Japan


Dictionary の初期化

Dictionary の生成とで一緒に初期化ができます。 生成の宣言の後に、From で繋ぎ {}(中括弧) で要素を ,(カンマ) で区切って記述します。 要素は { キー , 値 } の様に「キー」「値」をセットにします。

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        ' Dictionaryの生成
        Dim dic As New Dictionary(Of String, String) From _
                                {{"A", "America"}, {"C", "China"}, {"J", "Japan"}}
        ' For Each での順次処理
        For Each item In dic
            ' 要素
            Console.WriteLine("KEY:{0} のDictionaryの要素:{1}", item.Key, item.Value)
        Next
    End Sub

実行結果は以下の通りです。

KEY:A のDictionaryの要素:America
KEY:C のDictionaryの要素:China
KEY:J のDictionaryの要素:Japan



Dictionary の各メソッド・プロパティ等について

メソッド or
プロパティ
書式説明
Add Add(key As TKey, value As TValue)
 key:追加する要素のキー
 value:追加する要素の値(参照型の場合、null の値を使用可)
指定したキーと値をディクショナリに追加します
Clear Clear() Dictionary(Of TKey, TValue) から
すべてのキーと値を削除します
ContainsKey ContainsKey(key As TKey) As Boolean
 (プロパティ)
 key:Dictionary(Of TKey, TValue) 内で検索されるキー
戻り値:
 指定したキーを持つ要素が Dictionary(Of TKey, TValue) に
 存在する場合は true,それ以外は false
指定したキーが Dictionary(Of TKey, TValue)
での存在を確認します
Count Count As Integer  (これはプロパティ) Dictionary(Of T) に存在する要素の数を取得します
Item Item(key As TKey) As TValue  (プロパティ)
 key:取得または設定する値のキー
戻り値:
 指定したキーに関連付けられている値
 指定したキーが見つからなかった場合
  get 操作は KeyNotFoundException をスロー
  set 操作は指定したキーを持つ新しい要素を作成
 例外:ArgumentNullException
 index が 0 未満,または Dictionary(Of T).Count 以上
 例外:KeyNotFoundException
 プロパティが取得されたが,コレクション内に key が存在無し
指定したキーに関連付けられている値を
取得または設定します
Keys Keys As Dictionary(Of TKey, TValue).KeyCollection
 (プロパティ)
戻り値:
 Dictionary(Of TKey, TValue) 内のキーを
 格納しているDictionary(Of TKey, TValue).KeyCollection
Dictionary(Of TKey, TValue) 内のキーを
格納しているコレクションを取得します
Values Values As Dictionary(Of TKey, TValue).ValueCollection
 (プロパティ)
戻り値:
 Dictionary(Of TKey, TValue) 内の値を
 格納しているDictionary(Of TKey, TValue).KeyCollection
Dictionary(Of TKey, TValue) 内の値を
格納しているコレクションを取得します
Remove Remove(key As TKey) As Boolean
 key:削除する要素のキー
戻り値:
 要素が見つかり、正常に削除された場合は true,
 それ以外の場合は false
 key が Dictionary(Of TKey, TValue) に存在しない場合,false
指定したキーを持つ値を Dictionary(Of TKey, TValue) から削除します


上記のメソッド等を順を追って説明します。


ClearContainsKeyCount について

先ず Dictionary を生成しDictionaryの件数を Count プロパティで取得し、その後 ClearDictionary の要素を全て削除します。 尚、 ContainsKey プロパティで Clear 前後でキーの存在確認を行います。

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        ' Dictionaryの生成
        Dim dic As New Dictionary(Of String, String) From _
                                {{"A", "America"}, {"C", "China"}, {"J", "Japan"}}
        ' Dictionaryの件数
        Console.WriteLine("Dictionaryの件数:{0}", dic.Count)
        ' ContainsKey確認
        Dim key As String = "J"
        Console.WriteLine("キー[{0}]の存在確認:{1}", key, dic.ContainsKey(key))
        ' Clear
        Console.WriteLine("=== Clear ===")
        dic.Clear()
        Console.WriteLine("Dictionaryの件数:{0}", dic.Count)
        ' ContainsKey確認
        Console.WriteLine("キー[{0}]の存在確認:{1}", key, dic.ContainsKey(key))
    End Sub

実行結果は以下の通りです。また Clear 後は件数が「0」になります。

Dictionaryの件数:3
キー[J]の存在確認:True
=== Clear ===
Dictionaryの件数:0
キー[J]の存在確認:False


IndexOf コレクション要素のインデックスの検索

先ず Dictionary を生成しその要素の値指定でインデックスを IndexOf 関数で取得します。
その後、検索開始インデックスを指定する IndexOf での例を以下に示します。

    Private Sub btnDictionary_Click(sender As Object, e As EventArgs) Handles btnDictionary.Click
        Dim i As Integer = 0

        ' Dictionaryの生成(初期化)                   0   1    2     3      4  5   6    7
        Dim list As New Dictionary(Of Integer) From {1, 10, 100, 1000, 10000, 2, 20, 200}

        ' IndexOf(item As T)
        Console.WriteLine("=== IndexOf(item As T) ===")
        i = list.IndexOf(1000)
        Console.WriteLine("itemが「{0}」のインデックス:{1}", 1000, i)
        i = list.IndexOf(1500)
        Console.WriteLine("itemが「{0}」のインデックス:{1}", 1500, i)

        ' IndexOf(item As T, index As Integer)
        Console.WriteLine("=== IndexOf(item As T, index As Integer) ===")
        i = list.IndexOf(20, 4)
        Console.WriteLine("itemが「{0}」をインデックス「{1}」から検索した結果のインデックス:{2}", 20, 4, i)
        i = list.IndexOf(1000, 4)
        Console.WriteLine("itemが「{0}」をインデックス「{1}」から検索した結果のインデックス:{2}", 1000, 4, i)
    End Sub

実行結果は以下の通りです。
要素の値指定のみの IndexOf では先頭から検索する為「1000」の値の場合はインデックス「3」が返り、 「1500」の値の場合は Dictionary の要素に存在しないので「-1」が返ります。
検索開始インデックスを指定する IndexOf では開始インデックスを「4」とし、検索要素値「20」の場合は「6」が返り、 検索要素値「1000」の場合はインデックスを「4」以降には値が存在しないので「-1」が返ります。

=== IndexOf(item As T) ===
itemが「1000」のインデックス:3
itemが「1500」のインデックス:-1
=== IndexOf(item As T, index As Integer) ===
itemが「20」をインデックス「4」から検索した結果のインデックス:6
itemが「1000」をインデックス「4」から検索した結果のインデックス:-1


Insert 指定したインデックスの位置に要素を挿入

先ず Dictionary を生成しインデックス「5」の位置に「300」を挿入します。
その後、存在しないインデックス「10」の位置に挿入処理を行いエラーが発生することを確認します。

    Private Sub btnDictionary_Click(sender As Object, e As EventArgs) Handles btnDictionary.Click
        Dim i As Integer = 0

        ' Dictionaryの生成(初期化)
        Dim list As New Dictionary(Of Integer) From {1, 10, 100, 1000, 10000, 2, 20, 200}

        ' Insert(index As Integer, item As T)
        Console.WriteLine("=== Insert(index As Integer, item As T) ===")
        list.Insert(5, 300) 'インデックス「5」の位置に「300」を挿入
        i = 0
        For Each nVal As Integer In list
            Console.WriteLine("{0}番目に取得したDictionaryの要素:{1}", i, nVal)
            i += 1              '指標+1
        Next
        Try
            ' エラーが必ず発生
            list.Insert(10, 900) 'インデックス「10」の位置に「900」を挿入
        Catch ex As Exception
            Console.WriteLine("Insertエラー:{0}", ex.Message)
        End Try
    End Sub

実行結果は以下の通りです。
インデックス「5」の位置に「300」が挿入され、それ以降は順次繰り下がったことがわかります。
また、インデックス「10」の位置での挿入処理はエラーが返されています。

=== Insert(index As Integer, item As T) ===
0番目に取得したDictionaryの要素:1
1番目に取得したDictionaryの要素:10
2番目に取得したDictionaryの要素:100
3番目に取得したDictionaryの要素:1000
4番目に取得したDictionaryの要素:10000
5番目に取得したDictionaryの要素:300
6番目に取得したDictionaryの要素:2
7番目に取得したDictionaryの要素:20
8番目に取得したDictionaryの要素:200
Insertエラー:インデックスは一覧の範囲内になければなりません。
パラメーター名:index


Remove RemoveAt RemoveRange 要素の削除

先ず Dictionary を生成し Remove で値が「300」の要素を削除します。2回行うことで異なる結果が返ってくるはずです。 その後 RemoveAt でインデックス「5」の位置を削除処理を行い一覧確認します。 さらに存在しないインデックス「10」の位置を削除処理し、エラー発生を確認します。
その後 RemoveRange でインデックス「3」の位置から「2」個の要素を削除処理を行い一覧確認します。 さらにインデックス「3」の位置から存在しない個数の「5」で削除処理し、エラー発生を確認します。

    Private Sub btnDictionary_Click(sender As Object, e As EventArgs) Handles btnDictionary.Click
        Dim i As Integer = 0

        ' Dictionaryの生成(初期化)
        Dim list As New Dictionary(Of Integer) From {1, 10, 100, 1000, 10000, 300, 2, 20, 200}

        Dim blnRet As Boolean
        ' Remove(item As T)
        Console.WriteLine("=== Remove(item As T) ===")
        blnRet = list.Remove(300)
        Console.WriteLine("itemが「{0}」削除:{1}", 300, blnRet)
        blnRet = list.Remove(300)
        Console.WriteLine("itemが「{0}」削除:{1}", 300, blnRet)

        ' RemoveAt(index As Integer)
        Console.WriteLine("=== RemoveAt(index As Integer) ===")
        list.RemoveAt(5)
        Console.WriteLine("インデックス「{0}」の要素を削除", 5)
        i = 0
        For Each nVal As Integer In list
            Console.WriteLine("{0}番目に取得したDictionaryの要素:{1}", i, nVal)
            i += 1              '指標+1
        Next
        Try
            ' エラーが必ず発生
            list.RemoveAt(10) 'インデックス「10」の位置の要素削除
        Catch ex As Exception
            Console.WriteLine("RemoveAtエラー:{0}", ex.Message)
        End Try

        ' RemoveRange(index As Integer, count As Integer)
        Console.WriteLine("=== RemoveRange(index As Integer, count As Integer) ===")
        list.RemoveRange(3, 2)
        Console.WriteLine("インデックス「{0}」から「{1}」個の要素を削除", 3, 2)
        i = 0
        For Each nVal As Integer In list
            Console.WriteLine("{0}番目に取得したDictionaryの要素:{1}", i, nVal)
            i += 1              '指標+1
        Next
        Try
            ' エラーが必ず発生
            list.RemoveRange(3, 5)
        Catch ex As Exception
            Console.WriteLine("RemoveRangeエラー:{0}", ex.Message)
        End Try
    End Sub

実行結果は以下の通りです。

=== Remove(item As T) ===
itemが「300」削除:True
itemが「300」削除:False
=== RemoveAt(index As Integer) ===
インデックス「5」の要素を削除
0番目に取得したDictionaryの要素:1
1番目に取得したDictionaryの要素:10
2番目に取得したDictionaryの要素:100
3番目に取得したDictionaryの要素:1000
4番目に取得したDictionaryの要素:10000
5番目に取得したDictionaryの要素:20
6番目に取得したDictionaryの要素:200
RemoveAtエラー:インデックスが範囲を超えています。負でない値で、コレクションのサイズよりも小さくなければなりません。
パラメーター名:index
=== RemoveRange(index As Integer, count As Integer) ===
インデックス「5」から「2」個の要素を削除
0番目に取得したDictionaryの要素:1
1番目に取得したDictionaryの要素:10
2番目に取得したDictionaryの要素:100
3番目に取得したDictionaryの要素:20
4番目に取得したDictionaryの要素:200
RemoveRangeエラー:配列のオフセットおよび長さが範囲を超えているか、カウンターがソース コレクションのインデックスから最後までの要素の数より大きい値です。

関連する記事

コレクション「List」の使い方について
コレクション「List」と配列の相互変換について
コレクション「Dictionary」から配列及び List への変換について
配列の使い方について(Dim, Redim)
配列の使い方の注意点について(コピー, Clone)
配列の範囲指定によるコピー(Array.Copy, Skip, Take)











PR

コメント

コメントを書く