読者です 読者をやめる 読者になる 読者になる

BEACHSIDE BLOG

MicrosoftとかC#を好むレンジャーの個人的メモ

C# Dictionary の基礎

.NET C# Tips

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の実装だよね」といったゴリゴリしたことは省略です。

「キーとバリューをセットで保持できるんだよ。キーに基づいたバリューを検索したいときに便利だよ。」というのがわかりやすいところでしょうか。 キーもバリューもジェネリクスなので、どんな値でも入ります。 よくありそうな実例っぽいものだと、「Webシステムでユーザーの情報をキャッシュしておくのにDictionaryを使う」とかでしょうか。

ListやArrayなどのコレクションでもにたようなことはできますが、Dictionaryは以下の特徴があります。

  • 検索が早い
  • オブジェクトの生成は遅い

検索が早い理由は、内部でハッシュ値を持って、それを検索しているからです。TKeyをDictionaryに格納する際に、ハッシュ値を生成して内部で検索キーとして保持しています。 基礎なので、Dictionaryの内部では、

という構造体の配列をを保持しており….というゴリッゴリな内容は省略します。そんな構造してるから、オブジェクトの生成が遅いのは、そりゃそうだとなりますね。

2. 使用例の基礎

これはどこにでも書いてあるので、MSDNにおまかせしましょう。

https://msdn.microsoft.com/ja-jp/library/xfhwa508(v=vs.110).aspx#Anchor_8

ただし、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拡張メソッド

LinqToDictionaryメソッドについても簡単にサンプルを書いておきます。
以下のようなクラスがあるとします。

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

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