以前、「Unityで使える広義の配列」で書いたように、最近のC#では、ArrayListよりGeneric Listが推奨されている。
要素の型を指定できるので、よりロバストなコードがかけるGeneric Listだが、Generic Listの要素にGeneric Listを指定する、すなわち、Generic Listの入れ子はできるのだろうか?
答えはYes.
もともとGeneric ListはJavascript配列のように後から要素を追加(Add
メソッドを使う)できるのが便利。なので、Generic ListのGeneric Listが可能なら、いわゆる「ジャグ配列」のようなリストを作ることができる。
これをやりたかった理由として、ツリー階層構造にあるGameObjectから、下の階層のGameObjectを自動的に取り出してGeneric List化したかったことがある。たとえば、
のようなGameObjectの階層があり、このトップのMenuObject
のみから下の子GameObjectを自動的にリスト化したかった(なお、今回は階層数は固定とする)。
このスクリプトが次。
using UnityEngine; using System.Collections; using System.Collections.Generic; public class Test2 : MonoBehaviour { [SerializeField] protected Transform top; //'MenuObject'を指定 private List<GameObject> layer1; private List<List<GameObject>> layer2; // Use this for initialization void Start () { layer1 = new List<GameObject>(); //第1階層のGneric List layer2 = new List<List<GameObject>>(); //第2階層のGeneric List foreach(Transform elem1 in top) { layer1.Add(elem1.gameObject); List<GameObject> list = new List<GameObject>(); foreach(Transform elem2 in elem1) { list.Add(elem2.gameObject); } layer2.Add(list); } //チェック1 Generic List的に扱う foreach(List<GameObject> list in layer2) { foreach(GameObject elem in list) { Debug.Log("child:"+elem.name); //第2階層の要素 } } //チェック2 ArryList的に扱う for(int i = 0; i < layer1.Count; i++) { Debug.Log("layer1["+i+"] = "+layer1[i].name); //第1階層の要素 for(int j = 0; j < layer2[i].Count; j++) { Debug.Log("layer2["+i+"]["+j+"] = "+layer2[i][j].name); //第2階層の要素 } } } <<<以下略>>>
layer1
が第1階層のGameObjectのGeneric List、layer2
が第2階層のGameObjectからなるGeneric Listになる。
上の"Check Process"は、layer1, layer2の要素のGameObjectの名前をDebug.Logで出力するものだが、Generic ListはArrayListのように要素インデックスでも指定できる。(たとえば、layer2[i][j])。場合によってはインデックスで指定したほうが便利なときもあるので、使い分ければよいと思う。