【C#】Dictionaryは1種類だけじゃない!SortedとOrderedを用途に応じて使い分けよう!

当ページのリンクには広告が含まれています。

配列やListと並んで使われるDictionaryですが、実は用途に応じていくつかの種類が存在します。

今回は、C#で使えるDictionaryの種類と使い道について解説していきます。

用途に応じて使い分けることが大切ですので、是非覚えて活用して下さい。

目次

そもそもDictionaryとは

Listに検索キーを付加してものとして考えると分かりやすいです。

Dictionary(辞書)は、検索するためのキーと、それに対応する値を1つのペアとして保持するクラスです。

キーをKey、値をValueと呼ぶのですが、2つまとめてKeyValuePare と呼んだりもします。

Key、Value のどちらも任意の型やクラスを指定できます。

例えば、文字列で実数を検索したい場合、 Dictionary<string,double > と宣言しますし、例えば自分で作った Person というクラスがあったとすると、Dictionary<Person,string>の様に宣言します。

値の登録

辞書にキーと値を登録する場合は、Addメソッドを使います。

//Dictionaryの宣言
Dictionary<string,int> dic = new Dictionary<string,int>();

//"体重" というキーと、それに対応する値をDictionaryに登録
dic.Add("体重",68);

もう一つの方法として、添え字を使うことも可能です。この場合、新しい添え字を指定すれば、添え字をキーにして、代入した値が辞書に新規追加されますし、既にキーが存在していれば値が上書きされます。

dic["体重"] = 68;

値の取り出し

キーを添え字に指定することで瞬時に対応する値が取得できます。

//"体重" というキーでDictionaryから値を取り出す
int val = dic["体重"];

もし間違ったキーを添え字にしたらどうなるでしょう?

答えは例外エラーが発生してしまいます。

ですから、例えば画面から入力されたキーを使って検索するような場合は、あらかじめ ContainsKeyメソッドを使って、Dictionaryにキーがあるかを確認する必要があります。

if(dic.ContainsKey("体重") == true)
{
    double val = dic["体重"]
}

値の削除

登録した値を削除したい場合は、Removeメソッドを使います。

ただし、これもキーが存在しないとエラーになりますので、値の取り出しと同じく、場合によってContainsKeyでの存在確認が必要です。

//体重というキーを値ごと削除する
dic.Remove("体重");

全ての値を連続して取り出したい時

Dictionaryに登録されている全ての値を連続して取り出したい場合はfor ループを使います。

1つは、Keysプロパティを使ってキーを取り出し、そのキーを添え字にして値を取り出す方法です。

//辞書に登録されているKeyを取り出して、添え字に使う書き方
foreach (string key in dic.Keys)
{
    Console.WriteLine( dic[key]);
}

もう1つは、KeyValuePare を使ってキーと値をまとめて取り出す方法です。

//KeyValuePareを使った書き方
foreach (KeyValuePair<string,int> kvp in dic)
{
    Console.WriteLine( kvp.Value);
}

//KeyValuePareを var で省略した書き方
foreach (var kvp in dic)
{
    Console.WriteLine( kvp.Value);
}

辞書は登録順が保持されない

Dictionaryを使う上で、時には取り出す順番が重要になることがあります。

例えば、伝票番号と金額をDictonaryに保持しつつ、登録した順番に取り出したいとか、伝票番号でソートして取り出したいとかです。

悲しいことに、DictionaryはAddメソッドで登録した瞬間に、検索速度を優先した並び順で保持されるため、forループで取り出したときの順番は保証されません。

実際には、 foreachのループ内でキーと値を取り出す場合、登録順で取り出せることも多々ありますが、C#の仕様上 Dictionary は順序が保証されていないため、登録順で取り出すことが必須の処理ではDictionaryを使うべきではありません。

そこで、登録するたびに自動で並び替え(ソート)を行ってくれる SortedDictionaryと、登録した順番を保持してくれる OrderedDictionary が用意されています。

自動でキーをソートしてくれるSortedDictionary

SortedDictonary は、自動でKeyを昇順(1,2,3,4,5・・・)で並び替えてくれます。

//Dictonaryの宣言と値の登録
SortedDictionary<int, int> dic = new SortedDictionary<int, int>();
dic.Add(5, 500);
dic.Add(4, 400);
dic.Add(2, 200);
dic.Add(1, 100);
dic.Add(3, 300);
dic.Add(6, 600);

//キーと値を取り出すループ
foreach (KeyValuePair<int, int> kvp in dic)
{
    Console.WriteLine("key={0},value={1}",kvp.Key,kvp.Value);
}

答えは次の様になります。

key=1,value=100
key=2,value=200
key=3,value=300
key=4,value=400
key=5,value=500
key=6,value=600

登録順を保持してくれるOrderedDictionary

OrderedDictionaryは、Keyの登録順、つまりAddメソッドを実行した順番を保持してくれるものです。

ただ、残念ながら非ジェネリック版(宣言時にキーや値の型が指定できず、すべてobject型になる)なので、KeyValuePare での取り出しは出来ません。

ちょっとややこしいですが、次の様な書き方でキーと値を順番に取得できます。

//OrderedDictionaryを使う時は、次の2行を冒頭の参照に追加
using System.Collections;
using System.Collections.Specialized;

//OrderedDictionaryの初期化と値の登録
OrderedDictionary dic = new OrderedDictionary();
dic.Add(5, 500);
dic.Add(4, 400);
dic.Add(2, 200);
dic.Add(1, 100);
dic.Add(3, 300);
dic.Add(6, 600);

IDictionaryEnumerator enumerator = dic.GetEnumerator();

while (enumerator.MoveNext())
{
    Console.WriteLine("key={0},value={1}", enumerator.Key, enumerator.Value);
}

答えは次の様になります。

key=5,value=500
key=4,value=400
key=2,value=200
key=1,value=100
key=3,value=300
key=6,value=600

Linqを使うと通常のDictionaryでも並べ替えは可能

Dictionaryで並べ替えをしたいのであれば、Linqを使う事でも対応が可能です。

OrderBy(i=>i.Key) でキーによる並べ替え、OrderBy(i=>i.Value)で値による並べ替えができます。

Dictionary<int, int> dic = new Dictionary<int, int>();

dic.Add(5, 500);
dic.Add(4, 400);
dic.Add(2, 200);
dic.Add(1, 100);
dic.Add(3, 300);
dic.Add(6, 600);


foreach (KeyValuePair<int, int> kvp in dic.OrderBy(i=>i.Key))
{
    Console.WriteLine("key={0},value={1}", kvp.Key, kvp.Value);
}

OrderByは昇順になりますが、降順にしたい場合、OrderByDescendingが利用可能です。

foreach (KeyValuePair<int, int> kvp in dic.OrderByDescending(i=>i.Key))
{
    Console.WriteLine("key={0},value={1}", kvp.Key, kvp.Value);
}

まとめ

いかがでしたでしょうか。

通常のDictionaryは、検索しやすい並びで保持されているため、並び順が保証されていません。

その代わり、並び順を保証してくれる SortedDictionaryとOrderedDictionaryが用意されています。

もし、並び順が必要になったら、この記事を参考にして頂ければ幸いです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次