C#の基本イディオムについてその5~ディクショナリ~

C#では、要素のまとまりをコレクションというが、その1つとして、ディクショナリという考え方があるので、それについてまとめた。

## ディクショナリの宣言
ディクショナリは基本的に
「new Dictionary<(TKey)、(TValue)>」
の形式で書くこと。

~~~csharp
var hashira = new Dictionary<string, string>() {
       { "水柱", "冨岡義勇" },
       { "蟲柱", "誇張しのぶ" },
       { "炎柱", "煉獄杏寿郎" },
       { "音柱", "宇髄天元" },
       { "恋柱", "甘露寺蜜璃" },
       { "霞柱", "時透無一郎" },
       { "蛇柱", "伊黒小芭内" },
       { "風柱", "不死川実弥" },
       { "岩柱", "悲鳴嶼行冥" },
};
~~~

~~~csharp
foreach(var i in hashira)
{
      Console.WriteLine(i.Key); // Keyで、Tkeyの値にアクセスできる
      Console.WriteLine(i.Value); // Valueで、TValueの値にアクセスできる
}
~~~

今回の場合だと、i.Keyで「○柱」、i.Valueで柱の人の名前が取得できる。

また、ディクショナリはTValueの方にクラスを指定することもできる。

~~~csharp:JoJoクラス
public class Jojo
{
    public string Name { get; set; }
    public int Part { get; set; }

    public Jojo(string name, int part)
    {
         Name = name;
         Part = part;
    }
}
~~~
上記のようなJojoクラスがあったとして、

~~~csharp
var jojo = new Dictionary<string, Jojo>() {
    { "ファントムブラッド", new Jojo("ジョナサン・ジョースター", 1) },
    { "戦闘潮流", new Jojo("ジョセフ・ジョースター", 2) },
    { "スターダスト・クルセイダーズ", new Jojo("空条承太郎", 3) },
    { "ダイヤモンドは砕けない", new Jojo("東方仗助", 4) },
    { "黄金の風", new Jojo("ジョルノ・ジョバァーナ", 5) },
    { "ストーンオーシャン", new Jojo("空条徐倫", 6) },
    { "スティール・ボール・ラン", new Jojo("ジョニィ・ジョースター", 7) },
    { "ジョジョリオン", new Jojo("東方定助", 8) },
};
~~~
とディクショナリを宣言することができる。

## ディクショナリの操作
### 要素にアクセスする

~~~csharp
var giyu = hashira["水柱"]; // "冨岡義勇"にアクセスする
var part3 = jojo["スターダスト・クルセイダーズ"]; // jojoクラスのインスタンスが取得できる
~~~

### 要素を追加する

~~~csharp
hashira["爪柱"] = "臥龍岡爪太郎";
jojo["岸辺露伴は動かない"] = new Jojo("岸辺露伴", 9); 
~~~
もしくは

~~~csharp
hashira.Add("爪柱", "臥龍岡爪太郎");
jojo.Add("岸辺露伴は動かない", new Jojo("岸辺露伴", 9));
~~~

要素を追加するコレクションに既に存在しているキーを指定して追加した場合、例外(ArgumentException)が発生する。例外については別の記事でまとめる予定。

### 要素を削除する

~~~csharp
hashira.Remove("爪柱");
jojo.Remove("岸辺露伴は動かない");
~~~

削除する場合、まず、ディクショナリに指定したキーがあるかどうかを判定する。
キーがあれば、Trueを返しつつ、要素が削除する。
キーがない場合は、Falseを返すだけ。

## ディクショナリにもLINQを使うことができる。
LINQについては以下の記事にまとめてある。

https://qiita.com/RikiLog/items/71ec45ef0fcd775ee1ba

~~~csharp:(例1)
var average = hashira.Where(el => el.Key == "炎柱").FirstOrDefault(); // ["炎柱", "煉獄杏寿郎"]
~~~

~~~csharp:(例2)
var partSum = jojo.Sum(el => el.Value.Part);  // 36
~~~

## 配列やリストをディクショナリに変換する。
配列やリストはディクショナリに変換することが可能。

~~~csharp:Pokemonクラス
class Pokemon
{
    public string Name { get; set; }
    public string[] Types { get; set; }

    public Pokemon(string name, string[] types)
    {
        Name = name;
        Types = types;
    }
}
~~~
というポケモンクラスがあり、

~~~csharp
var pokemons = new List<Pokemon>() {
    new Pokemon("カメックス", new string[]{ "みず" }),
    new Pokemon("ミミッキュ", new string[]{ "ゴースト", "フェアリー" }),
    new Pokemon("ガブリアス", new string[]{ "ドラゴン", "じめん" }),
    new Pokemon("ヤドキング", new string[]{ "みず", "エスパー" }),
    new Pokemon("キングドラ", new string[]{ "みず", "ドラゴン" }),
    new Pokemon("マフォクシー", new string[]{ "ほのお", "エスパー" }),
    new Pokemon("ドリュウズ", new string[]{ "じめん", "はがね" }),
    new Pokemon("エレキブル", new string[]{ "でんき" }),
    new Pokemon("ブーバーン", new string[]{ "ほのお" }),
    new Pokemon("ベトベトン", new string[]{ "どく" }),
    new Pokemon("ハッサム", new string[]{ "むし", "はがね" }),
};
~~~
というList<Pokemon>型のpokemonsという変数があったとする。

このpokemonsをToDictionaryメソッドに変換することができる。

~~~csharp:pokemonsをディクショナリに変換
var poke = pokemons.ToDictionary(el => el.Name);

foreach(var item in poke)
{
      var type = "のタイプは,";

      foreach (var item2 in item.Value.Types)
      {
           var check = type == "のタイプは," ? "," : "";
           type = type + item2 + check;
      }

      var message = item.Key + type;

      Console.WriteLine(message);
}
~~~

~~~csharp:出力結果
カメックスのタイプは,みず,
ミミッキュのタイプは,ゴースト,フェアリー
ガブリアスのタイプは,ドラゴン,じめん
ヤドキングのタイプは,みず,エスパー
キングドラのタイプは,みず,ドラゴン
マフォクシーのタイプは,ほのお,エスパー
ドリュウズのタイプは,じめん,はがね
エレキブルのタイプは,でんき,
ブーバーンのタイプは,ほのお,
ベトベトンのタイプは,どく,
ハッサムのタイプは,むし,はがね
~~~

## 参考文献

https://gihyo.jp/book/2017/978-4-7741-8758-7

https://gihyo.jp/book/2019/978-4-297-10458-0