Unityな日々(Unity Geek)

Unityで可視化アプリを開発するための試行錯誤の覚書

Unityで使える広義の配列

参考:Choosing the right collection type - Unify Community Wiki

Unityの広義の配列―コレクション―はいくつか種類がある。それぞれ宣言や代入、値の取出しの記述が異なる。また、自由度が高い反面、使わないほうがよいものもある。



1)ビルトイン配列(Built-in Array)

もっとも基本的な配列で、もっとも高速。ただし宣言時に要素数を指定する必要がある。が、宣言後にリサイズは可能。(System.Array.Resize(ref myArray, size))で行う。)

C#での宣言、代入、リサイズは次のように行う。ただし、多次元のビルトイン配列はリサイズできない。

TheType myArray = new TheType[lengthOfArray];  // declaration
int[] myNumbers = new int[10];                 // declaration example using ints
GameObject[] enemies = new GameObject[16];       // declaration example using GameObjects
int howBig = myArray.Length;               // get the length of the array
myArray[i] = newValue;                     // set a value at position i
TheType thisValue = myArray[i];            // get a value from position i
System.Array.Resize(ref myArray, size);    //resize array
 
string[] weapons = new string[] { "Sword", "Knife", "Gun" };


2)Javascript配列(Javascript Array)

標準的な.netクラスにはない、Unity独自の配列。ただし名前通り、javascriptスクリプトでのみつかえ、C#型では使えない。

このため、サイズ変更可能、要素の型を宣言する必要がないなど柔軟性が高いが、反面、性能的にはもっとも遅い。

Javascript Arrayは基本的にはArrayListにラッパーをかけたものとみなせ、同様のことはObjectリストで実現できる。しかも速い。Javascript Arrayは「過去の遺産」と考えた方がよさそう。


3)アレイリスト(ArrayList

Javascript Array以上に柔軟性がある(たとえば要素数を変更できるなど)が、性能上は遅い(*)。またArrayList自体には型はなく、任意の型を要素として持つことができる。型の混在も可能。

ただし、Generic Listの登場によりArrayListの存在意義はなくなったといわれる。旧式のコードとの互換性上のものと考えた方がよさそう。

(*)性能面のハンデの多くは宣言時に要素数を宣言しないため、という報告もある。つまり、ArrayListでも要素数を固定すれば、速度は改善するらしい。

ArrayList myArrayList = new ArrayList();    // declaration
myArrayList.Add(anItem);                    // add an item to the end of the array
myArrayList[i] = newValue;                  // change the value stored at position i
TheType thisItem = (TheType) myArray[i];    // retrieve an item from position i
myArray.RemoveAt(i);                        // remove an item from position i
var howBig = myArray.Count;                 // get the number of items in the ArrayList


4)ハッシュテーブル(Hashtable)

'key-value'方式で要素を参照する配列。
key, valueともにどんな型でもよい(untype)。型の混在も可能。(keyは通常はString型であることがおおいが。)このため、Hashtableから要素を取り出す際は、ユーザがCastしてやる必要がある。
ただし、ArrayListよりもGeneric Listが良いのと同じように、近年は、HashtableよりDictionaryを使う方が良い。

Hashtable myHashtable = new Hashtable();                 // declaration
myHashtable[anyKey] = newValue;                          // insert or change the value for the given key
ValueType thisValue = (ValueType)myHashtable[theKey];    // retrieve a value for the given key
int howBig = myHashtable.Count;                          // get the number of items in the Hashtable
myHashtable.Remove(theKey);                              // remove the key & value pair from the Hashtable, for the given key.

5) ジェネリック・リスト(Generic List)

Generic Listは、Listとも呼ばれる。要素数可変、要素の追加・削除ができる点ではJavascript, ArrayListと同等の柔軟性がある。違いは、定義時に型を指定する点。宣言した型の要素しか保持できないため

  • 要素の値を取出す際、型キャストが不要。
  • ArrayListより速い

という利点がある。
つまり、特定の型のみ扱うことがわかっている場合は、ArrayListよりGeneric Listを使う方が良い。

using System.Collections.Generic;

List<Type> myList = new List<Type>();                 // declaration
List<int> someNumbers = new List<int>();              // a real-world example of declaring a List of 'ints'
List<GameObject> enemies = new List<GameObject>();    // a real-world example of declaring a List of 'GameObjects'
myList.Add(theItem);                                  // add an item to the end of the List
myList[i] = newItem;                                  // change the value in the List at position i
Type thisItem = List[i];                              // retrieve the item at position i
myList.RemoveAt(i);                                   // remove the item from position i


6) ジェネリック・ディクショナリー(Generic Dictionary)

HashtableのGneric List版。宣言時にkey, valueの型を指定する。このため、Gneric Listと同じ利点が得られる。

using System.Collections.Generic;

// declaration:
Dictionary<KeyType,ValueType> myDictionary = new Dictionary<KeyType,ValueType>();
 
// and a real-world declaration example (where 'Person' is a custom class):
Dictionary<string,Person> myContacts = new Dictionary<string,Person>();
 
myDictionary[anyKey] = newValue;                 // insert or change the value for the given key
ValueType thisValue = myDictionary[theKey];      // retrieve a value for the given key
int howBig = myDictionary.Count;                 // get the number of items in the Hashtable
myDictionary.Remove(theKey);                     // remove the key & value pair from the Hashtable, for the given key.


7) 2次元配列(2D Array)

以上はすべて1次元の配列について述べてきた。Unityでは2次元以上の配列を使うこともできる。以下は2次元配列についてのべるが、3次元、4次元…といった多次元配列を扱うこともできる。

「一般の」2次元配列の宣言では、外側・内側の2要素の要素数を指定する。

// declaration:
string[,] myArray = new string[16,4];            // a 16 x 4 array of strings
 
// and a real-world declaration example (where 'Tile' is a user-created custom class):
Tile[,] map = new Tile[32,32];                   // create an array to hold a map of 32x32 tiles
 
myArray[x,y] = newValue;                         // set the value at a given location in the array
ValueType thisValue = myArray[x,y];              // retrieve a value from a given location in the array
int width = myArray.GetLength(0);                // get the length of 1st dimension of the array 
int length = myArray.GetLength(1);               // get the length of 2nd dimension of the array


一方「ジャグ(jagged)」2次元配列では、(内側の)要素の数がそろっていなくても良い。

var myJaggedArray = [ [1, 2, 3], [4, 5], [6, 7, 8, 9, 10] ]; // a jagged int array

myArray[x][y] = newValue;
ValueType thisValue = myArray[x][y]; 

ちなみに、「ビルトイン配列(たとえば、GameObject[])を要素にもつジェネリック・リスト」を作るには次のように書く。

GameObject[] go1;
GameObject[] go2;
GameObject[] go3;
List<GameObject[]> gos = new List<GameObject[]>{go1,go2,go3};

以上、Unityで扱われる広義の配列について述べた。利用指針は次のようになるだろう。

・大きさがわかっているケースは、ビルトイン配列を使う。メモリ効率も速度ももっともよい。
ArrayListのかわりにGneric Listを、Hashtableの代わりにGeneric Dictionaryを使う。
Javascript Arrayは使わない。

要するに、型のキャストを避けるべき。
開発時はArrayListやHashtableを使ってもよいが、リリース時はGnericに変換するとよいだろう。