やさしいLINQ【超入門編】

# なぜLINQを学ぶのか
私個人の事情をいうとC#のパーサコンビネータSpracheをさわってみようとしたところ、構文がLINQを使用することが判明し、
先に今までなあなあな認識で甘えていたLINQを腰を据えて勉強しようと思った次第です。

LINQはforeachで基本的に書きなおせるため、C#を業務で使っている方でも*避けて通れる道*だと思いますが、
これを使えると**「できる人」っぽい雰囲気を出せる**(これ重要)のと**単純にコードが綺麗になり可読性が増す**(個人差があるかもしれませんが)ので
今まで「まだ覚えなくてもいいや」と思っていた人も**これを機会に覚えてしまってもいいと思います。**

ですが、とっつきずらさを考えて今回は最低限覚えておきたい内容のみを記述しておきました。
それ以外は新しく記事に書こうかなと思います。

# 前提知識
C#のコードを書いたことがあればおおよそOKでしょう。
遅延評価の項目で書いたコードにプロパティが若干あることくらいでしょうか懸念点としては。

~~筆者もこの記事を書くまでLINQの知識はほとんどありませんでした。
というよりはっきりいってこの記事を書きながら覚えていってます。~~
**2019/03/22更新しました。**

他言語の関数などと比較するときもありますが、基本的にはそういうもんなんだなと思ってくれればけっこうです。

# そもそもLINQとは？
[wiki](https://ja.wikipedia.org/wiki/%E7%B5%B1%E5%90%88%E8%A8%80%E8%AA%9E%E3%82%AF%E3%82%A8%E3%83%AA)を見ると
>様々な種類のデータ集合に対して標準化された方法でデータを問い合わせること（クエリ）を可能にするために、言語に統合された機能のことである。

けっこうざっくりですがわかりやすく書いてあります。
SQLをご存知のかたは言語機能にSQLが組み込まれたぐらいの感覚でいいと思います。
まあこれだけじゃわからないという人もこれから挙げていく例を見ればわかると思います。

また、LINQにはクエリ式とメソッド式がありますが、**今回はクエリ式に焦点を当てていきます。**
理由はそのほうがC#っぽいからというのとクエリ式の構文が理解できればメソッド式の構文もすぐに理解できると思ったからです。

ちなみに`クエリ構文`は

```c#:numbersから偶数を取り出すクエリ式
var evens = from number in numbers
            where number % 2 == 0
            select number;
```
のように`from`に始まり、`where`や`select`をつかって書かれた*クエリ式による構文*です。
一方、`メソッド構文`は

```C#:numbersから偶数を取り出すメソッド式
var evens = numbers.Where(number => number % 2 == 0)
                   .Select(number => number);
```
のように*メソッドベースの構文*になります。
他言語の経験がある方はメソッドベースの構文のほうが最初はしっくりくると思います。
ただしSQLと同じ感覚で行くと`from`に該当するものを記述しないことに注意。


# クエリキーワードを眺めていく
Linqを理解する一番の近道は
**クエリ式を記述するのに必要なキーワードがそれぞれどのような働きをするか理解する**
というのが個人的な見解です。

とりあえず[公式のドキュメント](https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/query-keywords)を参考にいろいろまとめてみました。

**正直、*`from`*と*`select`*、*`where`*を覚えておけばあとはなんとかなります。**
SQLをご存知のかたは最初にこの3つを覚えたと思います。
以下ではその3つを紹介していきます。他のキーワードは新しく記事にするかもしれません。

## from
**クエリ式は`from句`から始まります。**
クエリ式ではデータソース(xs)および範囲変数(x)を導入するために`from句`が必要になります。

```c#:from
from x in xs
```
ここでxはxsの連続する各要素への参照です。xの型は推論されるので指定する必要はありません。
**foreachのループの似ていますがクエリ式では基本的にループは発生しないです。**これに関しては後で書きます。

## select
**クエリ式は`select句`か`group句`のいずれかで終わります。**
`select句`では基本的にいままでのすべての句の評価から得た値に対して関数を適用します。

```c#:selectの簡単な例~関数fの適用~
var ys = from x in xs
         select f(x)
```
なにも適用しない場合は`select x`と記述すればOKです。引数をそのまま返す関数を適用しているともいえます。
他言語(Haskell, Lisp, Python, etc...)ならば`map`という関数があったりしますが役割としては同じものであると考えていいでしょう。

## where
**`where句`は述語を各要素に適用し、真を返すような要素を集めたものを返します。**

```c#:numbersから偶数を取り出すクエリ式(再掲)
var evens = from number in numbers
            where number % 2 == 0
            select number;
```
上の例でいれば、要素numberが偶数であるか？という条件が真であるような要素をフィルタリングしています。
他言語(Haskell, Lisp, Python, etc...)ならば`filter`という関数があったりしますが役割としては同じものであると考えてもいいでしょう。



# 遅延評価
LINQの最大の特徴として遅延評価というものがあります。
**実は基本的にクエリ式は即時に評価されるものではありません。**
連続した値(シーケンス)を返すクエリではクエリ変数そのものはクエリの結果を保持しません。クエリのコマンドが保持されるだけです。

**クエリ変数が`foreach`などのループによって評価されるまで**クエリの実行は**遅延**させられます。
これがいわゆる`遅延評価`で、関数型言語にふれたことがある方にとってはなじみ深い言葉だと思います。
逆に変数の値が得られた時点で即座に評価されるものを`正格評価`(先行評価)といったりします。

これだけじゃよくわからないよという方も、次のコードを見てもらえばだいたいこんな感じかなというのがわかってもらえると思います。
以下のコードはFooのリストからFoo.idのリストを`LINQ`で取得しようとしたものです。

```c#:コード例
class MainClass
{
	public static void Main (string[] args)
	{
		// Fooのリストを生成
		var seq = new List<Foo> {
			new Foo { Id = 2 }, new Foo { Id = 0 }, new Foo { Id = 1 },
		};
		// Fooのリストに対しクエリを発行
		var query = from x in seq
                    select x.Id;
		// ループ開始
		Console.WriteLine ("--- loop start! ---");
		foreach (var q in query) {
			Console.WriteLine ("{0}", q);
		}
	}
}

public class Foo {
	private int id;
	public int Id {
		get {
			Console.WriteLine ("call get id {0}", id);
			return id;
		}
		set => id = value;
	}
}

```

```shell:出力結果
--- loop start! ---
call get id 2
2
call get id 0
0
call get id 1
1

```
`LINQ`が**`遅延評価`ではなく`正格評価`を行うならば**結果は

```shell:正格評価版(実際はこうならない)
call get id 2
call get id 0
call get id 1
--- loop start! ---
2
0
1
```
となっていたでしょう。
`foreach文`で書きなおそうとすればこの違いはより明確になるはずです。
また、上のコード例のclass FooでC#の[プロパティ](https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/classes-and-structs/using-properties)を使用しました。
あまり馴染みがないという方はリンク先を参考にしてください。


ただし、**単一の値を返すクエリは即時実行されます。**
単一の値を返すクエリの例としては`Max`, `Average`, `First`, `Count`などです。
単一の値を返さないクエリを即時実行したい場合は`ToList`や`ToArray`、`ToDictionary`メソッドを呼びだせばOKです。


```c#:ToArrayで正格評価
var query = (from x in seq
             select x.Id).ToArray ();
```
上のようにqueryを書き直した場合は予想通り

```shell:ToArrayで正格評価
call get id 2
call get id 0
call get id 1
--- loop start! ---
2
0
1
```
といった結果になりました。
# さいごに
これで`LINQ`の基本的な部分は最低限抑えられたかなと思います。
`LINQ`の応用的な部分もこの基本的な部分を押さえていればすぐに理解できるはずです。

C#の記事を書いたのがはじめてであるのと、そもそも筆者のC#力がまだまだというのを考えると
けっこう変なこと言っている部分もあると思うのでどんどん指摘してもらって構いません。