Unity C# Dictionaryの使い方

##0.0 はじめに
データをまとめて扱うときに配列やListクラスがよく使われますが、それ以外にもDictionaryクラスがあります。
Dictionaryクラスではインデックス番号の代わりにKey（キー）と呼ばれる名前を使い、セットでValue（バリュー）と呼ばれる値を扱います。配列やListでindex（インデックス）番号で検索する代わりに、Key（例えば文字）で検索ができます。

👍**ポイント**
Keyには同じ値を使うことはできません。


##1.0 宣言及び初期化

Dictionary< Keyの型, Valueの型 > オブジェクト名 = new Dictionary< Keyの型, Valueの型 >()　

```C#:Test0.cs
// Dictionaryクラスの宣言と初期化
Dictionary<string, int> dic = new Dictionary<string, int>();
```


👍**ポイント**
Dictionaryクラスを使用した際にエラーが出る場合は、using System.Collections.Genericの呼び出しが消えていないか確認してみましょう（この宣言はUnityエディタとして使用するVisual Studioには標準で入っています。）

このように宣言と初期値の設定を同時にできます。


```C#:Test1.cs
// Dictionaryクラスの宣言と初期値の設定
Dictionary<string, int> dic = new Dictionary<string, int>(){
    {Apple, 150},
    {Orange, 100},
    {Peach, 250},       
};
```

##2.0 要素の追加
Addを使用して要素を追加することができます。
第一引数keyでは追加する要素のキーを指定します。第二引数valueでは追加する要素の値を指定します。
ただし、同じKeyの値を追加することはできません。

```C#:Test2.cs
// Dictionaryクラスでの要素の追加
dic.Add(Banana, 50);
```


##3.0 要素の取得
keyの指定でvalueが取得出来ます。
Dictionary[key]のように使います。

```C#:Test3.cs
// 要素の取得
int a = dic[Banana]; // aは50
```


####3.1 Keyのみの取得
Keyのみを取得するにはKeysプロパティが利用できます。

```C#:Test4.cs
// 要素の設定
Dictionary<string, int> dic = new Dictionary<string, int>(){
    {Apple, 150},
    {Orange, 100},
    {Peach, 250},       
};

// Keyの表示
foreach(string key in dic.Keys) {
    Debug.Log("キーは" + key + "です。)
}
// 　キーはAppleです。
// 　キーはOrangeです。
// 　キーはPeachです。
```

👍**ポイント**
Dictionaryクラスではindex番号(格納の順番)はありません。このためループ処理にはforeachを使います。

####3.2 Valueのみの取得
Valueのみを取得するにはValuesプロパティが利用できます。

```C#:Test5.cs
// Valueの表示
foreach(string value in dic.Values) {
    Debug.Log("バリューは" + value + "です。)
}
// 　バリューは150です。
// 　バリューは100です。
// 　バリューは250です。
```



####3.3 KeyとValueの両方の取得
KeyValuePair構造体を使ってKeyとValueの両方を取得する方法です。

```C#:Test6.cs
// 要素の取得
foreach(KeyValuePair<string, int> item in myTable) {
    Debug.Log("キーは" + item.Key + "です。  バリューは" + item.Value + "です。");
}
// 　キーはAppleです。　バリューは150です。
// 　キーはOrangeです。　バリューは100です。
// 　キーはPeachです。　バリューは250です。
```


##4.0 要素の削除
Removeを使います。

```C#:Test7.cs
// 要素の削除
dic.Remove("Banana"); // ()内はKey
```


##5.0 要素が含まれているかの確認
Containsを使います。

```C#:Test8.cs
dic.Add(Banana, 50);
// 要素の確認
bool flag = dic.Contains("Banana"); // flag = true
```


## おまけ
Dictionaryクラスではindex番号(格納の順番)がないので使いにくい場合があります。
index番号を持ったDictionaryクラスを自作しました。

```C#:MyDictionary.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//******************************
// 自作クラス DictionaryにIndex番号を搭載したクラス
// index(int)でkey(string)とvalue(int)を管理
// AddでKeyを追加していくと自動でDictionaryを生成する
// 要素数(keyの種類)はindexMaxで取り出す
//******************************
public class MyDictionary {
    //int index; // 要素番号(Addした順番に格納される)
    public int indexMax = 0; // keyの種類数
    List<string> Keys = new List<string>(); // keyの格納リスト
    List<int> Values = new List<int>(); // valueの格納リスト

    /// <summary>
    /// 要素を追加する(同じkeyがある場合はvalueを1増やす、ない場合は追加する)
    /// </summary>
    public void Add(string key) {
        if (Keys.Contains(key)) { // すでにKeyがあった場合はqtyを増やす
            Values[GetIndexByKey(key)]++;
        } else { // ない場合はKeyを新しく追加、qtyを１
            Keys.Add(key);
            Values.Add(1);
            indexMax++;
        }
    }

    /// <summary>
    /// 特定のkey(str)が含まれているか 含まれていればtrue
    /// </summary>
    public bool Contains(string key) {
        if (Keys.Contains(key))
            return true;
        return false;
    }

    /// <summary>
    /// keyのindex番号取得、含まれていない場合は-1を返す
    /// </summary>
    int GetIndexByKey(string key) {
        if (!Keys.Contains(key))
            return -1;
        return Keys.IndexOf(key);
    }

    /// <summary>
    /// 要素番号(index)からkeyを取得 引数：調べたいKeyの要素番号
    /// </summary>
    public string GetKeyByIndex(int index) {
        return Keys[index];
    }

    /// <summary>
    /// 要素番号(index)から数を取得 引数：調べたいKeyの要素番号
    /// </summary>
    public int GetQtyByIndex(int index) {
        return Values[index];
    }

    /// <summary>おまけ
    /// keyから全種類においての通し番号を取得 (１種類の最初の番号)
    /// keyがなければ-1を返す
    /// </summary>
    public int GetSerialIndexByKey(string key) {
        int serialIndex = 0; // 通し番号カウント用
        for (int i = 0; i < Keys.Count; i++) { // k
            if (Keys[i] == key) { // 同じkeyに当たれば検索終了
                break;
            }
            serialIndex += Values[i]; // なければそこまでの数をIndexに加える
        }
        // 以下keyが含まれてない場合-1を返す
        int sum = 0; // 全種類の合計数
        for (int i = 0; i < Values.Count; i++) {
            sum += Values[i];
        }
        if (serialIndex == sum) { // 最後まで言った場合はkeyがなかったということ
            return -1;
        } else
            return serialIndex;
    }

    // テスト用(Dicの中身をコンソール画面に表示する)
    public void Test() {
        for (int i = 0; i < indexMax; i++) {
            Debug.Log($"{i}番目のkeyは {Keys[i]} で、valueは {Values[i]} です");
        }
    }
}
```