連載
» 2006年03月31日 05時00分 UPDATE

.NET TIPS:ハッシュテーブル(連想配列)を使うには?(Dictionaryクラス編)[2.0のみ、C#、VB]

[遠藤孝信,デジタルアドバンテージ]
「.NET TIPS」のインデックス

連載目次

本稿は「TIPS:ハッシュテーブル(連想配列)を使うには?」に加筆・修正を行い、.NET Framework 2.0に対応させた改訂版です。


 ハッシュテーブルとは、キー(key)と値(value)のペアを保持しているコレクションである。通常の配列やリストがインデックス番号により各値(各要素)にアクセスできるのに比べて、ハッシュテーブルでは、インデックス番号の代わりにキーを用いて、その各値にアクセスすることができる。キーと、そのキーから連想される(キーに対応付けられている)値のペアを保持しているため、ハッシュテーブルは「連想配列」とも呼ばれる。ハッシュテーブルの特長は、指定したキーから、それに対応した値を高速に得られることである。

 .NET Framework 1.xのクラス・ライブラリでは、ハッシュテーブルはHashtableクラス(System.Collections名前空間)で実装されていたが、.NET Framework 2.0ではDictionaryジェネリック・クラス(System.Collections.Generic名前空間)が追加され、より効率的かつ安全にハッシュテーブルを扱えるようになっている。本稿では、このDictionaryジェネリック・クラスの基本的な利用方法についてまとめる。

ハッシュテーブルのインスタンス作成

 Dictionaryジェネリック・クラスは、コレクションの要素となるキーと値の型を型パラメータにより指定してインスタンスを作成する。以下は、キーも値も文字列の場合の記述例だ。

Dictionary<string, string> dict = new Dictionary<string, string>();

Dim dict As New Dictionary(Of String, String)

Dictionaryジェネリック・クラスのインスタンス生成(上:C#、下:VB)

 この場合には、以降のハッシュテーブル(この例ではdict)への操作で、文字列でないキーや値を扱うコードはコンパイル・エラーとなる。

ハッシュテーブルへの項目の追加

 ハッシュテーブルへの項目(キーと値のペア)の追加は、インデクサ(VBの場合は既定のプロパティとなっているItemプロパティ)か、Addメソッドにより行う。

dict["japan"] = "日本";
dict["america"] = "アメリカ";

dict.Add("china", "中国");
dict.Add("india", "インド");

dict("japan") = "日本"
dict("america") = "アメリカ"

dict.Add("china", "中国")
dict.Add("india", "インド")

ハッシュテーブルへの項目の追加(上:C#、下:VB)

 指定したキーがハッシュテーブルに存在しない場合には、新しい要素として登録される。キーがすでに存在する場合には、インデクサではそのキーに対応する値が置き換えられるが、Addメソッドでは例外が発生する。

ハッシュテーブル内の値の取得

 ハッシュテーブル内のあるキーに対する値の取得は、上記と同様にインデクサによりキーを指定して行う(逆に、値からキーを直接取得することはできない)。Hashtableクラスでは取り出した値はObject型となるため通常はキャストが必要となるが、Dictionaryジェネリック・クラスではキャストは不要だ。

string val = dict["japan"];

Dim val As String = dict("japan")

ハッシュテーブル内の値の取得(上:C#、下:VB)

 また、Hashtableクラスでは、指定したキーがハッシュテーブルに存在しない場合にはnull(VBではNothing)が返されるが、Dictionaryジェネリック・クラスでは例外が発生する。

 このため、指定したキーが存在するかどうかをチェックし、もし存在すればその値を取得するTryGetValueメソッドがDictionaryジェネリック・クラスには追加されている(記述例は下のサンプル・プログラムを参照)。

すべてのキーや値の列挙

 ハッシュテーブルに格納されているすべてのキーあるいは値は、コレクションとしてKeysプロパティあるいはValuesプロパティから取得できる。このため、foreachステートメント(VBではFor Each...Next)などを使って、すべてのキーや値を列挙することができる(記述例は下のサンプル・プログラムを参照)。

キーや値の存在チェック

 特定のキーや値を持つ項目がハッシュテーブルに格納されているかどうかを調べるには、ContainsKeyメソッドあるいはContainsValueメソッドを使用する。この2つのメソッドはbool型(VBではBoolean型)の値(TrueかFalse)を返す(記述例は下のサンプル・プログラムを参照)。

個々の要素の列挙

 ハッシュテーブル内の要素を列挙する場合には、各要素はKeyValuePairジェネリック構造体(System.Collections.Generic名前空間)のオブジェクトとして扱われる。この構造体は2つの型パラメータを持つが、それらはDictionaryジェネリック・クラスのインスタンス作成時に指定したものと同一となる。そして、KeyValuePairジェネリック構造体のオブジェクトからは、KeyおよびValueプロパティによりキーと値を取得できる(記述例は下のサンプル・プログラムを参照)。

 なお通常の配列などと異なり、ハッシュテーブルでは格納した要素の順序は保持されない。このためキーや値や要素を列挙した場合に、どのような順で要素が取り出されるかは不定である。

ハッシュテーブルを使ったサンプル・プログラム

 ここまでの解説をまとめたサンプル・プログラムを以下に示す。

// dictionary.cs

using System;
using System.Collections.Generic;

class DictionaryTest {
  static void Main() {

    Dictionary<string, string> dict = new Dictionary<string, string>();

    ////////////////////////////////////////
    // 要素の追加その1
    dict["japan"] = "日本";
    dict["america"] = "アメリカ";

    // 要素の追加その2
    dict.Add("china", "中国");
    dict.Add("india", "インド");

    ////////////////////////////////////////
    // 値の取得その1
    string val = dict["japan"];
    Console.WriteLine(val); // 出力:日本

    // string sss = dict["russia"]; // 例外発生

    // 値の取得その2
    string value = "";
    if (dict.TryGetValue("america", out value)) {
      Console.WriteLine(value); // 出力:アメリカ
    }

    ////////////////////////////////////////
    // キーの列挙
    foreach (string key in dict.Keys) {
      Console.WriteLine("{0} : {1}", key, dict[key]);
    }
    // 出力例:
    // japan : 日本
    // america : アメリカ
    // china : 中国
    // india : インド

    // 値の列挙
    foreach (string v in dict.Values) {
      Console.WriteLine(v);
    }
    // 出力例:
    // 日本
    // アメリカ
    // 中国
    // インド

    ////////////////////////////////////////
    // キーの存在チェック
    if (!dict.ContainsKey("france")) {
      // 存在しない場合
      dict["france"] = "フランス";
    }

    // 値の存在チェック
    Console.WriteLine(dict.ContainsValue("日本")); // 出力:True

    ////////////////////////////////////////
    // 項目(キーと値)の列挙
    foreach (KeyValuePair<string, string> kvp in dict) {
      Console.WriteLine("{0} : {1}", kvp.Key, kvp.Value);
    }
    // 出力例:
    // japan : 日本
    // america : アメリカ
    // china : 中国
    // india : インド
    // france : フランス

    ////////////////////////////////////////
    // ソート済みのハッシュテーブルの利用

    SortedDictionary<string, string> sdict = new SortedDictionary<string, string>(dict);

    foreach (KeyValuePair<string, string> kvp in sdict) {
      Console.WriteLine("{0} : {1}", kvp.Key, kvp.Value);
    }
    // 出力例:
    // america : アメリカ
    // china : 中国
    // france : フランス
    // india : インド
    // japan : 日本
  }
}

// コンパイル方法:csc dictionary.cs

ハッシュテーブルを使用したC#のサンプル・プログラム(dictionary.cs)
dictionary.csのダウンロード

' dictionary.vb

Imports System
Imports System.Collections.Generic

Class DictionaryTest
  Shared Sub Main()

    Dim dict As New Dictionary(Of String, String)

    '''''''''''''''''''''''''''''''''''''''
    ' 要素の追加その1
    dict("japan") = "日本"
    dict("america") = "アメリカ"

    ' 要素の追加その2
    dict.Add("china", "中国")
    dict.Add("india", "インド")

    '''''''''''''''''''''''''''''''''''''''
    ' 値の取得その1
    Dim val As String = dict("japan")
    Console.WriteLine(val) ' 出力:日本

    ' Dim sss As String = dict("russia") ' 例外発生

    ' 値の取得その2
    Dim value As String = ""
    If dict.TryGetValue("america", value)
      Console.WriteLine(value) ' 出力:アメリカ
    End If

    '''''''''''''''''''''''''''''''''''''''
    ' キーの列挙
    For Each key As String In dict.Keys
      Console.WriteLine("{0} : {1}", key, dict(key))
    Next
    ' 出力例:
    ' japan : 日本
    ' america : アメリカ
    ' china : 中国
    ' india : インド

    ' 値の列挙
    For Each v As String in dict.Values
      Console.WriteLine(v)
    Next
    ' 出力例:
    ' 日本
    ' アメリカ
    ' 中国
    ' インド

    '''''''''''''''''''''''''''''''''''''''
    ' キーの存在チェック
    If Not dict.ContainsKey("france")
      ' 存在しない場合
      dict("france") = "フランス"
    End If

    ' 値の存在チェック
    Console.WriteLine(dict.ContainsValue("日本")) ' 出力:True

    '''''''''''''''''''''''''''''''''''''''
    ' 項目(キーと値)の列挙
    For Each kvp As KeyValuePair(Of String, String) In dict
      Console.WriteLine("{0} : {1}", kvp.Key, kvp.Value)
    Next
    ' 出力例:
    ' japan : 日本
    ' america : アメリカ
    ' china : 中国
    ' india : インド
    ' france : フランス

    '''''''''''''''''''''''''''''''''''''''
    ' ソート済みのハッシュテーブルの利用

    Dim sdict As New SortedDictionary(Of string, string)(dict)

    For Each kvp As KeyValuePair(Of String, String) In sdict
      Console.WriteLine("{0} : {1}", kvp.Key, kvp.Value)
    Next
    ' 出力例:
    ' america : アメリカ
    ' china : 中国
    ' france : フランス
    ' india : インド
    ' japan : 日本
  End Sub
End Class

' コンパイル方法:vbc dictionary.vb

ハッシュテーブルを使用したVBのサンプル・プログラム(dictionary.vb)
dictionary.vbのダウンロード

 ちなみに.NET Framework 2.0のクラス・ライブラリには、キーによりコレクションの要素が自動的に並べ替えられるSortedDictionaryジェネリック・クラス(System.Collections.Generic名前空間)も用意されている。

 上記のサンプル・プログラムの最後の部分では、すでに存在するハッシュテーブルを基にこのクラスのインスタンスを作成し、その全要素を列挙している。その出力例から各項目はキーによりソートされているのが分かる。

利用可能バージョン:.NET Framework 2.0のみ
カテゴリ:クラス・ライブラリ 処理対象:コレクション
使用ライブラリ:Dictionaryクラス(System.Collections.Generic名前空間)
使用ライブラリ:KeyValuePair構造体(System.Collections.Generic名前空間)
使用ライブラリ:SortedDictionaryクラス(System.Collections.Generic名前空間)
関連TIPS:ハッシュテーブル(連想配列)を使うには?


「.NET TIPS」のインデックス

.NET TIPS

Copyright© 1999-2017 Digital Advantage Corp. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。