Unityな日々(Unity Geek)

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

ジェネリックリストのジェネリックリスト(ジェネリックリストの入れ子)を作る

以前、「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化したかったことがある。たとえば、

f:id:yasuda0404:20150306214040p:plain

のような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])。場合によってはインデックスで指定したほうが便利なときもあるので、使い分ければよいと思う。