LINQ

LINQとは

C#3.0からLINQというものが導入されました。
LINQは一言で言えば文法の拡張で、コレクション(データの集合)に対する操作を拡張するものです。
従来は数行必要だった処理を一行で簡潔に書けるようになります。
(コレクション=ListDictionaryなど、データをまとめて扱うもの)

LINQにはメソッド構文クエリ構文の二通りの書き方があります。
メソッド構文は従来のC#的なコードとほぼ同じ形式で、データの集合に対して便利なメソッドが多数提供されているイメージです。
クエリ構文はデータベース言語であるSQLに近い構文となっています。

まずはメソッド構文についての説明から行います。

より正確に言えば、LINQは様々なデータソースに共通の方法で操作する方法を提供するものです。
データソースとはプログラミングコード上の変数(配列)のほか、外部のデータベースやXMLなどです。
従来はそれぞれで異なるコードの記法をしていたものを共通の書き方ができるようにしたものがLINQです。

このサイトではそこまで突っ込んだ方法までは扱わないので、「何か便利なメソッドがたくさんある」という認識で問題ありません。

usingに追加

LINQを使用するにはコードの先頭に「using System.Linq;」が必要です。
もしなければ追加してください。


using System;
using System.Collections.Generic;
using System.Linq;
//↑なければ追加

シーケンス

LINQでは「コレクション(データの集合)」に対して操作をすると説明しましたが、LINQ的にはこれをシーケンスと呼びます。
シーケンスとは「要素を順番に取り出すことができるもの」という意味で、配列やListなどがそれにあたります。

LINQの例

LINQの機能のひとつ、Whereを使用してListの要素から偶数を取り出してみます。


List<int> nums = new List<int>()
{
    1, 2, 5, 9, 11, 14, 18, 21
};

//偶数を取り出す
IEnumerable<int> evens = nums.Where(n => n % 2 == 0);

foreach (var n in evens)
    Console.Write("{0} ", n);
2 14 18 

LINQ拡張メソッドの呼び出しは、通常の(Listクラスなどが提供する)メソッドと全く同じです。
Whereは指定のシーケンス(今回はnums)から条件に合う要素をすべて返します。

条件式には通常はラムダ式を使用します。
この例では

  1. numsから要素をひとつ取り出しnに格納
  2. その要素が2で割り切れるか否かを判定
  3. 割り切れるなら新しい(戻り値となる)シーケンスに追加
  4. 1~3をすべてのnums要素に対して実行
  5. 最後に3のシーケンスを返す

という処理を行っています。

Whereが返すのは「IEnumerable<データ型>」というデータ型です。
IEnumerable型自体もデータの集合です。
これはインターフェイスで、ListクラスやDictionaryクラスなどのLINQを使用できるデータ型はすべてIEnumerableインターフェイスを継承して作られています。
そのため、異なるコレクションクラスであっても共通のLINQのメソッドが使用できます。

List、配列に変換

IEnumerable<int>のままでもforeach文で値を取り出すことはできますが、添え字(インデクサ)で各要素にアクセスできません。
Listクラスを得たい場合はToListメソッドを呼び出します。
ちなみに配列を得たい場合はToArrayというメソッドもあります。


List<int> evenList =
    nums.Where(n => n % 2 == 0).ToList();
int[] evenArray = 
    nums.Where(n => n % 2 == 0).ToArray();

//ただのListなので
//添え字でアクセス可能
evenList[0] = 4;

ただし、IEnumerable型は可能ならばそのまま扱った方が高速に動作する可能性があります。
(Listや配列に変換するコストもかかります)


LINQのその他のメソッドは次ページで解説します。
数が多いですが、すべて覚える必要はなく必要に応じて調べると良いです。