テキスト篇:p.405「LINQとは」から
ゲーム開発演習:自弾の移動、アニメーション、複数化 など
p.405 LINQとは
・SQL(データベース操作言語)に近い構文によって、データ構造からの検索を行う仕掛け ・SQLの書式例: SELECT 項目名,… FROM 構造名 WHERE 項目名 条件演算子 値など 例: SELECT モンスター名,HP FROM モンスター表 WHERE HP > 100 ・SQLによる検索のポイント:値を返す関数やメソッドと異なり、データ構造が返される ・LINQの対象例: 配列、リストなどのコレクション、XML文書 など
p.406 LINQのクエリ
・クエリとはSQLにおける問い合わせのことで、データ構造が返される ・C#が提供するジェネリックインターフェイスを用いると、SQLに近い構文が使える
p.408 linq01.cs
//p.408 linq01.cs
using System;
using System.Linq; //LINQ構文用
using System.Collections.Generic; //IEnumerable<T>インターフェイス用
class linq01 {
public static void Main() {
int[] numbers = new int[] { -3, 4, 1, 2, -6, 3, 100, -25}; //クエリ対象の配列
// クエリの作成
IEnumerable<int> q = from n in numbers //配列numbersから
where n > 0 //要素値が正であるものを
select n; //得た結果の構造を返す
// クエリの実行
foreach (int x in q) { //IEnumerable<T>インターフェイス型オブジェクトから全要素(int型)について繰返す
Console.WriteLine(x);
}
}
}
p.406 LINQのクエリ(続き)
・LINQ構文を用いるには「using System.Linq;」を記述する(必須) ・LINQ構文で得られるデータ構造は、IEnumerable<T>インターフェイス型になる ・このジェネリクスに、クエリ対象の型を指定する ・配列を対象とする場合は、配列の要素型を指定すれば良い ・得られたIEnumerable<T>インターフェイス型のオブジェクトから、foreachなどで要素を取り出す処理を繰返すと良い ・クエリ式の基本書式: from 項目名 in 構造名 where 項目名 条件演算子 値 select 構造名 ・配列の場合のクエリ式の基本書式: from 作業変数 in 配列名 where 作業変数 条件演算子 値 select 配列名 ・なお、IQueryable<T>を用いることも可能 ※ VS2008ではp.407記載の手順が必要、VS2008より前のバージョンでは利用不可
p.409 データの並べ替えと個数
・LINQのメリットの一つはSQLのソート機能や関数機能などを利用できること ・構文: from 項目名 in 構造名 orderby 対象項目名 select 構造名 ・規定値は昇順(小⇒大)だが、対象項目名に descending を付記すると降順(大⇒小)になる ・得られたIEnumerable<T>インターフェイス型のオブジェクトで、Count()メソッドを呼ぶと件数が得られる ※ SQLでもCOUNT(*)構文で件数が得られる
p.409 linq02.cs
//p.409 linq02.cs
using System;
using System.Collections.Generic; //IEnumerable<T>インターフェイス用
using System.Linq; //LINQ構文用
class linq02 {
public static void Main() {
string[] myStr = {"flower", "cat", "dog", "bird", "rabbit"}; //クエリ対象の配列
// クエリの作成
IEnumerable<string> q =
from s in myStr //配列myStrから
where s.Length >= 4 //要素値の文字数が4以上であるものを
orderby s descending //要素値の降順に整列せよ
select s;
// クエリの実行
foreach (string x in q)
Console.WriteLine(x);
// 検索条件に適合した要素の個数
Console.WriteLine("適合した数={0}", q.Count());
}
}
p.410 var型の利用
・クエリが返すオブジェクトの型はIEnumerable<T>インターフェイス型と決まっている ・しかも、型パラメータの型もクエリによって自動決定できる ・よって、IEnumerable<T>型をvarキーワードで置き換えて良い ・これにより「using System.Collections.Generic;」も自動化されるので記述不要 ※ 加えて、foreachで用いる作業変数の型もvarキーワード指定で良い
アレンジ演習:p.409 linq02.cs
・IEnumerable<T>型をvarキーワードで置き換えてみよう
作成例
//アレンジ演習:p.409 linq02.cs
using System;
using System.Linq; //LINQ構文用
class linq02 {
public static void Main() {
string[] myStr = {"flower", "cat", "dog", "bird", "rabbit"}; //クエリ対象の配列
// クエリの作成
var q = from s in myStr where s.Length >= 4 orderby s descending select s;
// クエリの実行
foreach (var x in q) {
Console.WriteLine(x);
}
// 検索条件に適合した要素の個数
Console.WriteLine("適合した数={0}", q.Count());
}
}
p.410 Listコレクションからのデータ抽出
・配列と同様にList<T>型のコレクションオブジェクトをLINQで扱うことが可能 ・この場合、List<T>型に与えた型パラメータが自動的にクエリ結果の要素型になる ・List<T>型の利用には「using System.Collections.Generic;」が必要
p.411 linq03.cs
//p.411 linq03.cs
using System;
using System.Collections.Generic; //List<T>用
using System.Linq; //LINQ構文用
class data { //Listに格納するオブジェクトの型になるクラス
public string name;
public string address;
public int age;
}
class linq03 {
public static void Main() {
List<data> mydata = new List<data> { //クラスdataを要素型とするリスト
new data { name = "田中和夫", address = "東京都", age = 24}, //オブジェクト初期化子で生成
new data { name = "鈴木義男", address = "東京都", age = 17},
new data { name = "吉田育子", address = "青森県", age = 24},
new data { name = "田中和夫", address = "東京都", age = 34},
new data { name = "小林一郎", address = "北海道", age = 29}
};
// 旧式のデータ追加
data datax = new data();
datax.name = "粂井康孝";
datax.address = "北海道";
datax.age = 22;
mydata.Add(datax); //Listオブジェクトに格納
// 新方式のデータ追加
mydata.Add(new data { name = "猫山太郎", address = "青森県", age = 15 }); //オブジェクト初期化子で生成
var q = from x in mydata
where x.age < 30
orderby x.age ascending //※ascendingは省略可能
select x; //クエリを実行
Console.WriteLine("氏名\t\t住所\t年齢");
foreach (data z in q) {
Console.WriteLine("{0}\t{1}\t{2}", z.name, z.address, z.age);
}
}
}
p.412 メソッド構文の利用
・LINQのクエリ構文はC#の文法と馴染まないので、可読性のために、メソッドをドットでつなぐ形式のメソッド構文も利用できる
・書式例:
構造名.Where(条件メソッド名).Select(選択メソッド名);
・条件メソッドの書式例:
static bool 条件メソッド名(型 作業変数) { return 作業変数を用いた条件式; }
・選択メソッドの書式例:
static 項目型 選択メソッド名(型 作業変数) { return 作業変数; }
・ソートなども可能
・書式例:
構造名.Orderby(整列メソッド名).Select(選択メソッド名);
構造名.OrderbyDesending(整列メソッド名).Select(選択メソッド名); //降順用
・整列メソッドの書式例:
static 項目型 整列メソッド名(型 作業変数) { return 作業変数; }
p.413 linq04.cs
//p.413 linq04.cs
using System;
using System.Linq; //LINQ構文用
class linq04 {
static bool MyWhere(int x) { //条件メソッド
return (x > 0); //作業変数を用いて条件(正の数のみ)を表す
}
static int MyOrderBy(int x) { //整列メソッド
return x; //引数で得た作業変数を返すのみ
}
static int MySelect(int x) { //選択メソッド
return x; //引数で得た作業変数を返すのみ
}
public static void Main() {
int[] numbers = new int[] {200, -3, 4, 1, 2, -6, 3, 100, -25}; //クエリ対象の配列
//メソッド構文
var q = numbers.Where(MyWhere) //条件メソッドを指定
.OrderByDescending(MyOrderBy) //整列メソッドを指定し降順でソート
.Select(MySelect); //選択メソッドを指定
//クエリの実行
foreach (int x in q) {
Console.WriteLine(x);
}
}
}
p.415(メソッド構文における匿名メソッドの利用)
・メソッド構文で別記している各メソッドは、匿名メソッド(p.304)にすることで簡略化できる
・書式例:
構造名.Where(delegate(型 引数){return 条件式;}).Select(delegate(型 引数){return 引数;});
・デリゲートにより、各メソッドを別記する必要がなくなる
p.415 linq05.cs
//p.415 linq05.cs
using System;
using System.Linq; //LINQ構文用
class linq05 {
public static void Main() {
int[] numbers = new int[] {200, -3, 4, 1, 2, -6, 3, 100, -25}; //クエリ対象の配列
//メソッド構文
var q = numbers.Where(delegate(int x) { return x > 0; }) //条件をデリゲートで指定
.OrderByDescending(delegate (int x) { return x; }) //整列メソッドをデリゲートで指定し降順でソート
.Select(delegate (int x) { return x; }); //選択をデリゲートで指定
//クエリの実行
foreach (int x in q)
Console.WriteLine(x);
}
}
p.415(メソッド構文におけるラムダ式の利用)
・匿名メソッドはラムダ式(p.306)にすることで、よりシンプルにできる ・書式例: 構造名.Where(引数 => 条件式).Select(引数 => 引数); ・型の自動判定ができるので、引数型は省略可能 ・「引数 => 引数」は一律に「x => x」「w => w」などとしてOK
p.415 linq06.cs
//p.415 linq06.cs
using System;
using System.Linq; //LINQ構文用
class linq05 {
public static void Main() {
int[] numbers = new int[] {200, -3, 4, 1, 2, -6, 3, 100, -25}; //クエリ対象の配列
//メソッド構文
var q = numbers.Where(x => x > 0) //条件をラムダ式で指定
.OrderByDescending(x => x) //整列をラムダ式で指定し降順でソート
.Select(x => x); //選択をラムダ式で指定
//クエリの実行
foreach (int x in q)
Console.WriteLine(x);
}
}