前回はインターフェースとポリモーフィズムについて学びましたが、今回の記事ではListについて解説していきます。
前回の記事:
Listは配列をより使いやすくしたコレクションの一つになります。
配列より便利なListクラスとは
Listクラスは配列と似たものになります。各要素にアクセスする時に添字を使用するのも同じです。
Listクラスは配列を便利にしたもので、大きな違いとしては以下のものがあります。
- 要素数の追加ができる。List.Addメソッド、List.Insertメソッドなど
- 要素の削減ができる。List.RemoveAtメソッドなど
- 要素数の確認。Countプロパティを使用する。(Lengthではない)
また、通常のクラスとは異なりテンプレートと呼ばれるC#の機能を利用しています。
テンプレートは強力な機能で実装する際には色々と注意点がありますが、利用する際には型名の後に<>
の中に型を指定したものを書くだけでいいです。
テンプレートの使い方の例:new List<int>(), new List<float>()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
List<int> list = new List<int>(); //初期化の後に要素を追加する時はAddメソッドを使用する。(末尾に追加される。) list.Add(10); // <- list = { 10 } //要素にアクセスする時は配列と同じ int n = list[0]; // <- n == 10 //Insertメソッドを使用すると指定した場所に要素を挿入できる。 list.Insert(0, 20); // <- list = { 20, 10 } //リストの要素数はCountプロパティから取得できる int count = list.Count // <- count == 2 //要素を削除する時はRemoveメソッドを使用する。 list.RemoveAt(0); // <- 添字で指定して要素を削除している。 list = { 10 } list.Remove(10); // <- 値を指定して要素を削除している。 list = {}<br> |
Listのサイズと実際に確保している要素数について
ListクラスではCountプロパティが要素数を表していますが、実際に確保している個数はそれより多い場合があります。
リストは配列とは異なり要素数が使用していく内に変化する可能性があるのですが、その都度毎回要素を確保することはコンピュータ的に負荷が高い処理になります。この問題を回避するためにListクラスでは一度の要素確保の際にCountプロパティの値以上を確保する場合があります。
実際に確保されている要素数を確認する際はCapacityプロパティを使用してください。
また、CountプロパティとCapacityプロパティの値を一致させたい時はTrimExcessメソッドを使用してください。
1 2 3 4 5 6 7 8 9 |
//listが持つ要素を変更していく。 // その中でlist.Countとlist.Capacityの値が異なるかもしれない。 var list = new List<int>() { 1, 2, 3, 4, 5 }; list.Add(100); list.RemoveAt(2); list.Add(200); //CountとCapacityを一致させたい時はTrimExcessメソッドを使用する。 list.TrimExcess(); // <- CountとCapacityが一致する。 |
Listクラスが継承しているインターフェースについて
Listクラスは次のインターフェースを継承しています。基本的にC#の標準ライブラリが提供するコレクション型を表すものになります。これらのインターフェースが所属する名前空間はSystem.Collections
およびSysten.Collections.Generic
になります。
- IList
- IList<T>
- IReadOnlyList<T>
- ICollection
- ICollection<T>
- IReadOnlyCollection<T>
- IEnumerable
- IEnumerable<T>
Listクラスに対してどんなメソッドやプロパティが実装されているかはこのインターフェースを見ればわかります。
また、必要があれば機能のオーバーライドを行うこともできますね。
デリゲートを引数に渡すメソッドについて
Listクラスおよび多くのC#のクラスでは、デリゲート(※)という「メソッドを表す値」を引数に取るメソッドが数多く定義されています。
(※デリゲートについては「UnityC# デリゲートとイベントとUnityActionの使い方」で詳しく解説します。デリゲートにはクラスのメソッドやラムダ関数、無名関数などが使用できます。)
それらのメソッドでは呼び出し元がそのメソッドが行う処理を部分的にカスタマイズできます。カスタマイズできる部分をデリゲートとして渡します。
また、デリゲートとして渡すメソッドは引数としてリストにある要素一つを渡し、それに応じて戻り値を返すものが多いです。
Listクラスでは次のメソッドにデリゲートを渡すことができます。
- Exists:デリゲートに渡したメソッドがtrueを返す要素があるか確認する。
- Find:デリゲートに渡したメソッドがtrueを返す要素を返す。複数ある場合は最初に見つかったものを返す。
- FindIndex:デリゲートに渡したメソッドがtrueを返す要素の添字を返す。複数ある場合は初めに見つかったものを返す。
- FindAll:デリゲートに渡したメソッドがtrueを返す要素を全て返す。
- RemoveAll:デリゲートに渡したメソッドがtrueを返す要素を全て削除する。
- ForEach:全ての要素をデリゲートに渡したメソッドに渡して処理する。foreach文の古い書き方。
- ConvertAll:全ての要素に対してデリゲートに渡したメソッドを使って値を変換する。
1 2 3 4 5 6 7 |
using System.Collections; using System.Collections.Generic; var list = new List<int>() { 0, 1, 2, 3, 4, 5 }; var b = list.Exists(n => n == 1); // <= b == true var index = list.FindIndex(n => n == 4); // <= index == 4 |
ここで紹介したListクラスのメソッドをより便利にしたものとしてLinqと呼ばれるC#の機能があります。Linqについては「UnityC#のLinq・属性・拡張メソッド・クラスの部分定義の使い方」で解説していきます。
【実践】Unityで実際にListを使ってみる
それでは実際にUnityでListクラスを使ってみましょう!
今回のサンプルコードではListクラスに複数のMeshRendererを設定することができます。
ListクラスはUnityエディタのInspector表示に対応しているので、Unityエディターからシーン上にある好きなMeshRendererを設定できます。
ただし、自分自身を複製すると、無限ループに陥ってしまいUnityが停止してしまうので注意してください。
また、配列との違いを表すため、Startメソッド内でListクラスのAddメソッドを使用し、スクリプト上からGameObjectを作成しています。
GameObject作成部分ではUnityEngine.Object.Instantiate
メソッドを使用して、Prefabフィールドに設定されたGameObjectを複製しています。
Prefabフィールドにはプレハブ(Prefab)というUnity特有のアセットも使用できますが、それについては他の記事でご紹介したいと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Sample : MonoBehaviour { public List<MeshRenderer> Meshes; //Sampleコンポーネントが管理しているMeshRenderer public MeshRenderer Prefab; //自動生成時に使用するプレハブ public Color Color; public int CreateInstanceCount = 3; public float Interval = 1f; void Start() { if(Prefab != null) { //Prefabと同じ内容のGameObjectを指定した個数分横一列に作成する。 var pos = Vector3.zero; for (var i=0; i<CreateInstanceCount; ++i) { pos = Vector3.right * i * Interval; var inst = Object.Instantiate(Prefab, pos, Quaternion.identity); // <- プレハブの複製 Meshes.Add(inst); } } //MeshesにあるMeshRendererの色をColorに変更する。 foreach (var mesh in Meshes) { mesh.material.color = Color; } } } |
まとめ
今回の記事ではListについて解説してきました。
簡単にまとめますと以下のようになります。
- Listクラスは配列を便利にしたもの。
- C#のテンプレート機能を利用している。
- 基本的な使い方は配列と同じ。
- 配列とは違い要素の追加・削除ができる。
- 要素数の確認にはCountプロパティを利用する。
- コンピュータの都合からCountプロパティ以上の要素数を確保している場合がある。
- 実際に確保している要素数を確認したい時はCapacityプロパティを利用する。
- CountとCapacityプロパティの個数を一致させたい時はTrimExcessメソッドを使用する。
それでは次の記事に行ってみましょう!
コメント