C#のLINQを使ってみる

ayumegu(プログラマー)
よろしくお願いします。

C#の本を読んでいたらUnityで使えるLINQという便利なもの見つけたので使ってみました。

並べ替えや条件を指定しての取得が簡単にできる便利クラスみたいです。
これを使えばループや分岐が一気に減らせます
javascriptでもimportすれば使える!

参考サイト  

事前準備

C#の場合
using System.Linq;

JavaScriptの場合
import System.Linq;

これを書くだけで使える
よし早速使ってみよう!

シーンの準備

とりあえずサンプルとしてオブジェクトを配置
赤い四角にEnemyというタグをつけてみた
緑の球体にはPlayerタグをつけてあります  
空のGameObjectに下記スクリプトをアタッチ

1
2
3
4
void Start () {
  GameObject[] transformArray = GameObject.FindGameObjectsWithTag ("Enemy");
  Debug.Log (transformArray.Length);
}

シンプルにEnemyタグのついたGameObjectを全部取得するだけの処理です

実行結果は8です。
ここまでは下準備

LINQ使ってみよう

先ほどのを同じようにLINQで書くと

1
2
3
   GameObject[] transformArray2 = GameObject.FindGameObjectsWithTag ("Enemy")
      .Select(go => go)
      .ToArray();

Transformのリストを取得する場合は

1
2
3
   Transform[] transformArray2 = GameObject.FindGameObjectsWithTag ("Enemy")
      .Select(go => go.transform)
      .ToArray();

で取得することができる。
ここからがもっと便利

Playerとの距離が10以下のEnemyObjectを取得する場合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private GameObject player;

void Start () {
  player = GameObject.Find("Player");

  Transform[] transformArray = GameObject.FindGameObjectsWithTag("Enemy")
      .Select(go => go.transform)
      .Where(t => Vector3.Distance(t.position , player.transform.position) < 10.0f)
      .ToArray();
  
  // わかりやすく黄色にする
  for (int i = 0; i < transformArray.Length; i++) {
      GameObject obj = transformArray[i].gameObject;
      obj.renderer.material.color = Color.yellow;
  }

実行結果

まだまだこれだけじゃなくて並べ替えて取得することもできる
わかりやすく距離を20に修正し、距離を出力  

1
2
3
4
5
6
7
8
9
10
   Transform[] transformArray = GameObject.FindGameObjectsWithTag("Enemy")
      .Select(go => go.transform)
      .Where(t => Vector3.Distance(t.position , player.transform.position) < 20.0f)
      .ToArray();

  for (int i = 0; i < transformArray.Length; i++) {
      GameObject obj = transformArray[i].gameObject;
      obj.renderer.material.color = Color.yellow;
      Debug.Log (Vector3.Distance(obj.transform.position , player.transform.position));
  }


このままでは取得できる順番はバラバラ
OrderByで並び方を指定すると…

1
2
3
4
5
   Transform[] transformArray = GameObject.FindGameObjectsWithTag("Enemy")
      .Select(go => go.transform)
      .Where(t => Vector3.Distance(t.position , player.transform.position) < 20.0f)
      .OrderBy(t => Vector3.Distance(t.position , player.transform.position)
      .ToArray();


きれいに並びました。  

ほかにもたくさんメソッドがあって一覧はこのサイトにきれいにまとまっていました
LINQの拡張メソッド一覧と、ほぼ全部のサンプルを作ってみました。 – 地平線に行く

今回の感想

LINQ便利。リストや配列に使えるのでいままでforやforeachで回して処理していた部分が一気になくなります。
書き方がSQLみたいな感じのようなちょっと気持ち悪い感じではあるけれど。

C#は言語自体あまりしっかり学習できていないのでこれを機会にいろいろ試してみようと思います。