Hashtableクラスを利用して、キーと値のペアで構成される項目を1つ以上格納する「連想配列」を取り扱う方法を解説する。
本稿は2004/02/20に初版公開、2005/05/26に改訂された記事を再改訂し、Visual Studio 2017でコードの動作検証、図版の追加、全般的な構成の変更などを行ったものです。
※本稿の内容に加筆・修正を行い.NET Framework 2.0に対応させた「TIPS:ハッシュテーブル(連想配列)を使うには?(Dictionaryクラス編)」もご覧ください。
ハッシュテーブルとは、キー(key)と値(value)のペアを保持しているコレクションである。通常の配列がインデックス番号により各値(各要素)にアクセスできるのに比べて、ハッシュテーブルでは、インデックス番号の代わりにキーを用いて、その各値にアクセスできる。キーと、そのキーから連想される(対応付けられている)値のペアを保持しているため、ハッシュテーブルは「連想配列」とも呼ばれる。ハッシュテーブルの特長は、指定したキーから、それに対応した値を高速に得られることである。
.NET Frameworkのクラスライブラリでは、ハッシュテーブルがHashtableクラス(System.Collections名前空間)で実装されている。本稿では、このHashtableクラスの基本的な利用方法についてまとめる。
特定のトピックをすぐに知りたいという方は以下のリンクを活用してほしい。
なお、.NET Framework 2.0以降ではDictionaryクラス(System.Collections.Generic名前空間)を使う方がよい。詳しくは「TIPS:ハッシュテーブル(連想配列)を使うには?(Dictionaryクラス編)」をご覧いただきたい。
ハッシュテーブルへの項目(キーと値のペア)の追加は、インデクサ(VBの場合は既定のプロパティとなっているItemプロパティ)か、Addメソッドにより行う。なお、C#のコードでは「using System.Collections;」行が必要となる。
Hashtable ht = new Hashtable();
ht["japan"] = "日本";
ht.Add("china", "中国");
Dim ht As Hashtable = New Hashtable
ht("japan") = "日本"
ht.Add("china", "中国")
指定したキーがハッシュテーブル(この例ではht)に存在しない場合には、新しい要素として登録される。キーが既に存在する場合には、インデクサではそのキーに対応する値が置き換えられるが、Addメソッドでは例外が発生する。重複するキーが存在しないと分かっている初期化の際などにはAddメソッドを使い、後から追加/変更するときにはインデクサを使うとよいだろう。なお、この例ではキーと値の両方に文字列を用いているが、実際にはObject型のキーと値が指定可能であるため、どのようなオブジェクトでもHashtableオブジェクトに格納できる。
なお、C# 3/VB 10以降ではハッシュテーブルのインスタンス作成と同時に項目を追加可能だ。その構文を使って、上のコードを書き直すと次のようになる(「Dictionaryクラスを簡単に初期化するには?」や「構文:コレクションのインスタンス化と同時に要素を追加するには?[C#/VB]」なども参照してほしい)。
Hashtable ht = new Hashtable
{
  ["japan"] = "日本",
  ["america"] = "アメリカ"
};
Dim ht As Hashtable = New Hashtable From {
  {"japan", "日本"},
  {"america", "アメリカ"}
}
ハッシュテーブル内の値の取得は、上記と同様にインデクサ(VBではItemプロパティ)によりキーを指定して行う(逆に、値からキーを直接取得することはできない)。今述べたように、ハッシュテーブルは要素をObject型のオブジェクトとして保持しているため、必要なら元の型に変換しなければならない。
string val = (string)ht["japan"];
Dim str As String = CType(ht("japan"), String)
指定したキーがハッシュテーブルに存在しない場合には、null(VBではNothing)が返される。
ハッシュテーブルに格納されている全てのキーあるいは値は、コレクションとしてKeysプロパティあるいはValuesプロパティからアクセスできる。このため、foreachステートメント(VBではFor Each……Nextステートメント)などを使って、全てのキーや値を列挙することができる(記述例は下のサンプルプログラムを参照)。
特定のキーや値がハッシュテーブルに格納されているかどうかは、ContainsKeyメソッドあるいはContainsValueメソッドを使用する。この2つのメソッドはbool型(VBではBoolean型)の値(TrueかFalse)を返す(記述例は下のサンプルプログラムを参照)。
ハッシュテーブルに格納されている全てのキーと値をいっぺんに列挙したいときは、ハッシュテーブル内の要素(エントリ)を列挙すればよい(記述例は下のサンプルプログラムの最後を参照)。この場合には、ハッシュテーブル内の各要素はDictionaryEntry構造体(System.Collections名前空間)のオブジェクトとして取り扱われる。
なお、逆引き(値からキーを得る)には、この方法で全てのキーと値を列挙しながら調べる。
ここまでの解説をまとめたサンプルプログラム(C#版およびVB版)を以下に示す。Visual Studio 2017でVBプロジェクトを新規作成して、以下のコードを試す場合には、Mainプロシージャ内のコードをコピー&ペーストしてほしい。
// hashtable.cs
using System;
using System.Collections;
public class test {
  static void Main() {
    Hashtable ht = new Hashtable();
    // データの追加その1
    ht["japan"] = "日本";
    ht["america"] = "アメリカ";
    // データの追加その2
    ht.Add("china", "中国");
    ht.Add("india", "インド");
    // データの取得
    string val = (string)ht["japan"];
    Console.WriteLine(val); // 出力:日本
    // キー項目の列挙
    foreach (string key in ht.Keys) {
      Console.WriteLine(key);
    }
    // 出力例:
    // india
    // japan
    // america
    // china
    // 値項目の列挙
    foreach (string value in ht.Values) {
      Console.WriteLine(value);
    }
    // 出力例:
    // インド
    // 日本
    // アメリカ
    // 中国
    // キーの存在チェック
    if (!ht.ContainsKey("france")) {
      ht["france"] = "フランス";
    }
    // 値の存在チェック
    Console.WriteLine(ht.ContainsValue("日本")); // 出力例:True
    // エントリ(キーと値)の列挙
    foreach (DictionaryEntry de in ht) {
      Console.WriteLine("{0} : {1}", de.Key, de.Value);
    }
    // 出力例:
    // india : インド
    // japan : 日本
    // france : フランス
    // america : アメリカ
    // china : 中国
  }
}
// コンパイル方法:csc hashtable.cs
' hashtable.vb
Imports System
Imports System.Collections
Class HashTableSample
  Shared Sub Main()
    Dim ht As Hashtable = New Hashtable
    ' データの追加その1
    ht("japan") = "日本"
    ht("america") = "アメリカ"
    ' データの追加その2
    ht.Add("china", "中国")
    ht.Add("india", "インド")
    ' データの取得
    Dim str As String = CType(ht("japan"), String)
    Console.WriteLine(str) ' 出力:日本
    ' キー項目の列挙
    For Each key As String In ht.Keys
      Console.WriteLine(key)
    Next
    ' 出力例:
    ' india
    ' japan
    ' america
    ' china
    ' 値項目の列挙
    For Each val As String In ht.Values
      Console.WriteLine(val)
    Next
    ' 出力例:
    ' インド
    ' 日本
    ' アメリカ
    ' 中国
    ' キーの存在チェック
    If Not ht.ContainsKey("france") Then
      ht("france") = "フランス"
    End If
    ' 値の存在チェック
    Console.WriteLine(ht.ContainsValue("アメリカ")) ' 出力:True
    ' エントリ(キーと値)の列挙
    For Each de As DictionaryEntry In ht
      Console.WriteLine("{0} : {1}", de.Key, de.Value)
    Next
    ' 出力例:
    ' india : インド
    ' japan : 日本
    ' france : フランス
    ' america : アメリカ
    ' china : 中国
  End Sub
End Class
' コンパイル方法:vbc hashtable.vb
なお、キーも値も文字列に限定できる場合には、StringDictionaryクラス(System.Collections.Specialized名前空間)も便利に使える。このクラスはHashtableクラスをラップし、メソッドやプロパティで扱う型をString型に限定したものだ。
カテゴリ:クラスライブラリ 処理対象:コレクション
使用ライブラリ:Hashtableクラス(System.Collections名前空間)
使用ライブラリ:DictionaryEntry構造体(System.Collections名前空間)
使用ライブラリ:StringDictionaryクラス(System.Collections.Specialized名前空間)
関連TIPS:ハッシュテーブル(連想配列)を使うには?(Dictionaryクラス編)[2.0のみ、C#、VB]
関連TIPS:Dictionaryクラスを簡単に初期化するには?
関連TIPS:ハッシュテーブル(Dictionaryクラス)を値でソートするには?
関連TIPS:要素を重複なく管理するには?(HashSetクラス編)[3.5、C#、VB]
【2018/08/01】Visual Studio 2017でのコードの動作検証、図版の追加、全般的な構成の変更などを行いました。
【2005/05/26】本記事の一部に以下のような誤りがありました。おわびして訂正させていただきます。 
誤:  指定したキーがハッシュテーブル(この例ではht)に存在しない場合には、新しい要素として登録される。キーがすでに存在する場合には、それに対応する値が置き換えられる。
正:  指定したキーがハッシュテーブル(この例ではht)に存在しない場合には、新しい要素として登録される。キーが既に存在する場合には、インデクサではそのキーに対応する値が置き換えられるが、Addメソッドでは例外が発生する。
【2004/02/20】初版公開。
Copyright© Digital Advantage Corp. All Rights Reserved.