C# の LINQ の基本
LINQ のクエリ演算子
LINQ は IEnumerable インターフェイスや IQueryable インターフェイスを実装したクラスからなるデータのシーケンスを、 異なるデータシーケンスに変換する作業を容易にします。
データシーケンスを作り出すメソッドをクエリ演算子 (Query operator) といいます。
C# の LINQ では多数のクエリ演算子が用意されいます。あらかじめ用意されているクエリ演算子を「標準クエリ演算子」といいます。
クエリ演算子は拡張メソッドとして実装されています。System.Linq 名前空間を参照することで、標準クエリ演算子が利用できるようになります。
LINQ の Where を用いたデータの抽出
LINQ を使って、配列からデータを抽出してみましょう。
LINQ を利用する場合には using System.Linq を書き、 System.Linq を利用できるようにします。
これにより配列に対して、 Where() メソッドが利用できるようになります。
Where() メソッドは型 T の配列に対しては、 T 型の要素を受け取り、 bool を返すデリゲートを引数にとります。
「string を受け取り bool を返すデリゲート」ということでそのまま delegate(string s) { return true; } のようにしても良いですし、 ラムダ式を使っても良いです。多くの場合ラムダ式を使う書き方が一般的なので、当サイトでもラムダ式を基本として使います。
引数のデリゲートに配列の要素がひとつずつ渡され、デリゲートが true を返す要素のみが抽出されます。
次の例では、配列 fruits の要素をひとつずつチェックして、 B で始まる要素で true を返しています。 このため、抽出結果の a は "Banana" という要素だけを持つ配列になります。
using static System.Console;
using System.Linq;
partial class TestApp
{
static void Main(string[] args)
{
var fruits = new string[] { "Apple", "Banana", "Orange" };
var a = fruits.Where(elm => elm.StartsWith("B"));
foreach (var s in a)
{
WriteLine($"{s}");
}
// Banana
}
}
このように、 LINQ の Where クエリー演算子を用いて、元の配列からデータを抽出することができます。
LINQ の Select を用いた配列の作成
あるデータシーケンスを元にして、新しいデータシーケンスを作成するには Select クエリ演算子を使います。
JavaScript をご存知の方は map() 関数のようなものであると考えるとわかりやすいと思います。
次の例では、 fruits という配列を元にして、 id と fruit というプロパティを持つオブジェクトからなる配列を作成します。
using static System.Console;
using System.Linq;
partial class TestApp
{
static void Main(string[] args)
{
var i = 0;
var fruits = new string[] { "Apple", "Banana", "Orange" };
var a = fruits.Select(elm =>
{
return new
{
id = ++i,
fruit = elm
};
});
foreach (var s in a)
{
WriteLine($"{s}");
}
}
}
LINQ のクエリ式
LINQ の標準クエリ演算子は上の例でみた Where() や Select() メソッドのように拡張メソッドとして実装されます。
この他、LINQ ではいくつかのクエリ演算子に対して、クエリ式 (Query expression) が用意されています。
クエリ式は from、 select、orderby などのキーワードで構成され SQL に似た書き方になります。
クエリ演算子のメソッドは C# のメソッドらしくパスカルケースを用いて書きますが、クエリ式は全て小文字で書きます。
上で見たデータ抽出の例をクエリ式を使って書くと,次のようになります。
using static System.Console;
using System.Linq;
partial class TestApp
{
static void Main(string[] args)
{
var fruits = new string[] { "Apple", "Banana", "Orange" };
var a = from elm in fruits
where elm.StartsWith("B")
select elm;
foreach (var s in a)
{
WriteLine($"{s}");
}
// Banana
}
}
また、上で見た Select によるシーケンスの作成は次のようになります。
using static System.Console;
using System.Linq;
partial class TestApp
{
static void Main(string[] args)
{
var i = 0;
var fruits = new string[] { "Apple", "Banana", "Orange" };
var a = from elm in fruits
select new
{
id = ++i,
fruit = elm
};
foreach (var s in a)
{
WriteLine($"{s}");
}
}
}
この例のように、クエリ式でははじめに from キーワードと in キーワードを用いて、 クエリ演算子の引数として渡されるデリゲートに渡る変数と対象のシーケンスを指定します。
その後に、デリゲートの本体部分を並べて記述する形式になります。