C# の Dictionary の 入門 編的なショートセッションを...職場でやることにしたので、やる内容をメモです。
Overview
Dictionary の基礎を知ってもらうための座学として、
1. Dictionaryの基礎知識
2. 使用例の基礎
3. SortedDictionary、SortedList
をまとめました。
1. Dictionaryの基礎知識
IDictionary<TKey, TValue>
インターフェースを実装したクラスDictionary<TKey, TValue>
です。
基礎なので、「いやいや、インターフェースは、IDictionary<TKey,TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue>, ISerializable, IDeserializationCallbackの実装だよね」といったゴリゴリしたことは省略です。
「キーとバリューをセットで保持できるんだよ。キーに基づいたバリューを検索したいときに便利だよ。」というのがわかりやすいところでしょうか。 キーもバリューもジェネリクスなので、どんな値でも入ります。
ListやArrayなどのコレクションでもにたようなことはできますが、Dictionaryは以下の特徴があります。
- 検索が早い
- オブジェクトの生成は遅い
検索が早い理由は、内部でハッシュ値を持って、それを検索しているからです。TKey
をDictionaryに格納する際に、ハッシュ値を生成して内部で検索キーとして保持しています。
基礎なので、Dictionaryの内部では、
という構造体の配列を保持しており....というゴリッゴリな内容は省略します。そんな構造してるから、オブジェクトの生成が遅いのは、そりゃそうだとなりますね。
2. 使用例の基礎
これはどこにでも書いてあるので、公式ドキュメントにおまかせしましょう。
公式ドキュメント: Dictionary<TKey,TValue> Class の 使用例
ただし、C#6.0からインデックス初期化子を使ってよりいい感じで書けるようになりましたので、それは身につけましょう(という個人的思想)。
具体的には、お兄さまのサイトにて見るのがよいです。
ufcpp.net
Dictionaryをforeachすると...
ここでちょっとしたTipsその1です。
Dictionary
をforeachすると、KeyValuePair
が取得されます。これは、Dictironary
自体がIEnumerable.GetEnumerator()
するときに、DictionaryくんがKeyValuePair
を型指定しているからですが...
(「内部でstructの配列を保持してるのに、GetEnumeratorでKeyValuePair生成かいっっ」...てあんまり面白くなかったでしょうか...)
比較規則のカスタマイズ...
Tipsその2です。
インデクサを使ってDicotionay
を検索する際、大文字小文字も厳密に評価されるので、
(正確には、評価されるのはそのキーのハッシュ値ですが...)
この場合Keyが存在しないので、exceptionが発生します。
大文字小文字を「そんなの関係ねー」と叫んで検索したい場合は、コンストラクターでIEqualityComparer
を渡してあげると、評価方法をカスタマイズして値をとることができます。
ToDictionary拡張メソッド
LinqのToDictionary
メソッドについても簡単にサンプルを書いておきます。
以下のようなクラスがあるとします。
そのリストをToDictionaryしたい場合、これだけです。簡単ですね。
3. SortedDictionary、SortedList
IDictionaryの血筋(?)、Dictionary
には、実は兄弟がいます。
- SortedDictionary<TKey, TValue>
- SortedList<TKey, TValue>
これらは、ハッシュコードを使っていません。内容がソートされているので、そもそも高速に検索が可能です。ただし、二つとも共通して言えるのは、常にソートした値を保持するためオブジェクトの生成がおそーいです。
この2つで何が違うかは...そもそもの構造が違います。SortedList
はKeyとValueにそれぞれIList
インターフェースを実装して値をもっているので、多様な検索ができる分、キーの追加や削除をすると、がっつり移動しなければならないため高コストになります。
SortedDictionary
は、ツリー構造なので SortedList
より高速です。しかし、ツリー構造を持ってるだけにメモリの利用量が多いです。
あと、.NET4.5からはIReadOnlyDictionary<TKey, TValue>
ができ、名前の通りReadOnlyです。大きなDictionaryを使うことが少ない私は個人的にこれを使うことが多いです。
どれが優れているとかではないので、ケースバイケースでより目的にあったものを使いましょう。