【Unity】C# Dictionaryの使い方 まとめ

C#

Unityでのゲーム開発において、変数の値を効率的に管理する方法の一つがDictionaryです。
Dictionaryは、キーに基づいて値にかなり高速にアクセスできるコレクションであり、ゲーム開発の多くの場面で活躍の場があります。

スポンサーリンク

Dictionaryとは?

C#のDictionary<TKey, TValue>は、キーと値のペアをコレクションとして保持するためのジェネリックコレクションです。TKey, TValueはジェネリック型で、キーと格納する値の型を示します。
キーは一意でなければならず、これにより特定の値への高速なアクセスが可能になります。

使い方

宣言と初期化

using System.Collections.Generic;

Dictionary<string, int> myDictionary = new Dictionary<string, int>();
Dictionary<string, int> myDictionary2 = new Dictionary<string, int>(){{"key1", 1}, {"key2", 2}};
Dictionary<string, int> myDictionary3 = new Dictionary<string, int>(100);
Dictionary<string, int> myDictionary4 = new Dictionary<string, int>(myDictionary2);

使用する際はSystem.Collections.Genericをusingに含む必要があります

Dictionary型の宣言ではサイズを指定せずに宣言することも可能ですが、
myDictionary3のように予めサイズを指定することも可能です。
予め要素数が決まっている場合はサイズを指定した方がパフォーマンス効率がよくなります

要素の追加(Add, TryAdd)

Add

myDictionary.Add("apple", 3);

“apple”というキーで3の値を追加します。
既にmyDictionaryに”apple”というキーが存在する場合、エラーになります。

TryAdd

myDictionary.TryAdd("apple", 3);

“apple”というキーで3の値を追加し、追加できた場合trueを返します
既にmyDictionaryに”apple”というキーが存在する場合でもエラーにはならず、falseを返します

要素の削除(Remove, Clear)

Remove

myDictionary.Remove("apple");

“apple”というキーで要素を削除し、成功したらtrueを返します
キーが存在しない場合、falseを返します

Clear

myDictionary.Clear();

全ての要素を削除します。

要素の取得(キー指定, TryGetValue, Keys, Values)

キーの指定

int value = myDictionary["apple"];

“apple”というキーでアクセスして値を取得します。
キーが存在しない場合、エラーになります。

TryGetValue

int value;
myDictionary.TryGetValue("apple", out value);

“apple”というキーでアクセスして値を取得し、取得できた場合trueを返し、値はvalueに格納されます。
キーが存在しない場合でもエラーにはならず、falseを返します。

Keysプロパティ/Valuesプロパティ

foreach (var key in myDictionary.Keys)
{
    Console.WriteLine(key); // すべてのキーを表示
}

foreach (var value in myDictionary.Values)
{
    Console.WriteLine(value); // すべての値を表示
}

DictionaryのKeysプロパティで全てのキーValuesプロパティで全ての値を取得できます。

要素数の取得(Count)

Count

int count = myDictionary.Count;

要素数を返します

また、Linqメソッドを使うことで下記のように条件を満たしている要素数を数えることも可能です。

using System.Linq;

int count = myDictionary.Count(x => x.Value >= 2);  //値が2以上の要素数を数える
int count2 = myDictionary.Count(x => x.Key.Contains("a"));  //キーにaという文字が含まれる要素数を数える

要素の存在判定 (ContainsKey, ContainsValue, Any)

ContainsKey

myDictionary.ContainsKey("apple");

指定したキーの要素が存在するかを判定します。

ContainsValue

myDictionary.ContainsValue(1);

指定した値の要素が存在するかを判定します。

Any

myDictionary.Any(x => x.Key.Contains("a"));  // キーに"a"が含まれるものが1つでもあるか
myDictionary.Any(x => x.Value >= 2);  // 値が2以上のものが1つでもあるか

指定した条件を満たす要素が1つでもあるかどうかを判定します。

UnityでのDictionary

インスペクター

UnityのインスペクターではDictionary型の操作は出来ません

SerializeFieldなDictionary型をメンバに持たせてオブジェクトにアタッチしても

このようにインスペクター上には何も表示されません
そのため、インスペクターでDictionaryを扱いたいときは工夫が必要です。

解決方法の一つとして、ジェネリック型のKeyとValueを持つ、Serializableなクラスを定義する方法があります。

[Serializable]
public class MyDictionary<TKey, TValue>
{
    [SerializeField] private TKey _key;
    [SerializeField] private TValue _value;

    public TKey Key => _key;
    public TValue Value => _value;
}

public class DictionaryObject : MonoBehaviour
{
    [SerializeField] private List<MyDictionary<string, int>> _myDictionaries;
    private Dictionary<string, int> _dictionary = new Dictionary<string, int>();

    void Awake()
    {
        foreach (var myDictionary in _myDictionaries)
        {
            _dictionary.Add(myDictionary.Key, myDictionary.Value);
        }
    }
}

このようにすることでインスペクター上から疑似的にDictionary型の値を追加したり、削除することが出来ます

Dictionaryを使う際の注意点

キーの管理が複雑になりがち

Dictionary型では同じキーをAddしようとしたり、存在しないキーに対してアクセスしようとするとエラーになり、Unityでは動作が止まる原因にもなります
そのため、キーは適切に管理しないといけないですが、ContainsKeyで存在判定をしてからAddしようとすると、それだけで複数行使ってしまうので、プログラムが少し煩雑になっていきます。

敢えてこういう場合はエラーを出したいみたいなケースを除くと、TryAddやTryGetValueを使うのが安全で楽ですね。

本当にDictionaryを使うべきか

Dictionary型はキーでのアクセスが確定している場合、List型に比べてかなり高速で動作します。
ただし、Linqなどを使ってDictionary型のValuesの中から条件を満たすものを探す、などのような使い方をする場合はもともとList型で保持しておいてFindする方が動作が高速です。

どのように要素を検索するか、どのように要素を格納するかをしっかり検討した上でDictionary型は使うようにしましょう。
インスペクターでそのまま使えないこと、キーの管理などを考えると、基本的にはListを使うだけで十分かもしれません。

C#基礎知識
スポンサーリンク
フーシャ

主にUnityを触ってるクライアントエンジニア。
学部の情報工学科卒業後、
スマホ向けゲームの開発/運営会社に新卒で入社して現在5年目の社会人です。

フーシャをフォローする
フーシャをフォローする

コメント

タイトルとURLをコピーしました