BEACHSIDE BLOG

Azure と GitHub と C# が好きなエンジニアの個人メモ ( ・ㅂ・)و ̑̑

C# Dictionary の基礎

C# の Dictionary の 入門 編的なショートセッションを...職場でやることにしたので、やる内容をメモです。

f:id:beachside:20161108085639j:plain

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を使うことが少ない私は個人的にこれを使うことが多いです。

どれが優れているとかではないので、ケースバイケースでより目的にあったものを使いましょう。