Hashtable(ハッシュテーブル)
ハッシュテーブルとは、たとえば文字列をキーにデータを取り出すデータ構造のことです。通常の配列では添え字に数字を使い、hoge[0]やfuga[23]などとしたり、定数を用いてconst N = 10; foo[N]などとしますが、ハッシュテーブルではこの添え字が文字列になるというイメージを持っていただくと良いかと思います。例えばanimals["dolphin"]でイルカのデータを取り出せたり、students["Taro"]で太郎君の成績データを取り出せたりするというイメージです。このとき、添え字に当たる部分をキー(Key)、取り出したデータを値(Value)と呼びます。
このハッシュテーブル、いざ自分で実装しようとなると、意外に面倒です。なぜなら、データに文字列そのままではアクセスできないので、内部で必ず文字列を数字に変換するハッシュ関数を用意する必要があるからです。加えて、得られる数字がかぶらないように工夫したり、同じ数字が出た場合にどう対処するかなど、使う用途によってちょっとしたテクニックが必要になります。場合によっては、応答速度のオーダまで要求されることもあるでしょう。
そんなとき、コレクションで用意されているHashtableを使えば、こういった心配をせず、同様のデータ構造を手軽に実現できるのです。加えて、Hashtableは文字列以外のオブジェクトをキーにして、対になるオブジェクトを値として取り出すことができますから、かなり柔軟な処理に対応することができます。筆者自身、後に紹介するQueue、Stackと並んで、このコレクションをよく使っています。
Hashtableサンプルプログラムの解説
Hashtable ht = new Hashtable(); // ハッシュテーブルを用意
/* 値を格納していく */
ht.Add("Dolphin", "海豚");
ht.Add("Dog", "犬");
ht.Add("Cat", "猫");
ht.Add(1, "ONE");
ht.Add(2, "TWO");
ht.Add(3.14, "PI");
/* 次のような格納方法もある */
ht[true] = false;
ht[false] = true;
Console.WriteLine("英単語をキーに、漢字データを取り出す");
Console.WriteLine("Dolphin:{0}\nDog:{1}\nCat:{2}\n", ht["Dolphin"], ht["Dog"], ht["Cat"]);
Console.WriteLine("数字をキーに、英単語データを取り出す");
Console.WriteLine("1:{0}\n2:{1}\n3.14:{2}\n", ht[1], ht[2],ht[3.14]);
Console.WriteLine("真偽値をキーに、逆の真偽値を取り出す");
Console.WriteLine("True:{0}\nFalse:{1}", ht[true], ht[false]);
英単語をキーに、漢字データを取り出す Dolphin:海豚 Dog:犬 Cat:猫 数字をキーに、英単語データを取り出す 1:ONE 2:TWO 3.14:PI 真偽値をキーに、逆の真偽値を取り出す True:False False:True
注目していただきたいのは、オブジェクトならなんでもキーとして利用できるという点です。文字列、整数はもちろん、浮動小数、真偽値、場合によっては自作のオブジェクトもキーとして利用できます。Hashtableに値を格納するときはAddメソッドか、配列の要領で直接指定をします。このとき、キーは空やnullではいけませんが、値は未指定でも問題ありません。キーだけ設定して値を未指定とした場合、その要素は値としてnull参照を返します。
Hashtableの基本的な使い方
基本的には、
Add(key, value)で値を格納するHashtable[key]として値を参照するRemove(key)で指定要素を削除する
という使い方をします。
このほか、Countで内包している要素の数が取得できますし、ContainsKey/ContainsValueメソッドでキーや値が既に含まれているかどうかのチェックが可能です。また、Clearメソッドで内容をすべて消去することができます。コンストラクタでは事前にHashtableの大きさを指定することが可能で、要素の数が指定した大きさ内に収まる時にはAddメソッドの動作速度がO(1)になります(指定した大きさより大きい領域ではO(n)です)。またRemoveメソッドで削除する場合と値を取り出すときは、O(1)で動作します。
Hashtableを使う上での注意点
登録されていないキーに対しては、キーだけ設定して値を設定しなかった時と同じくnull参照を返してくれますので、NullReferenceに気をつけておけば、広範囲に実害が出る可能性は低いです。このあたりは、領域外参照に対して例外を返すコレクションに比べて扱いやすいと思いますが、それによって発見しにくいバグが混入する可能性もありますので、利用の際はキーの型と格納するデータの型をあらかじめ決めてしまうなど、十分注意して使ってください。
