LINQとは、さまざまなデータソースを共通の方法で処理できる仕組みです。
| データソース | 技術 | 参照 |
|---|---|---|
| オブジェクト (.NETコレクション、ファイル、文字列など) | LINQ to Objects | |
| データセット (DataSet) | LINQ to DataSet | |
| SQL Server | LINQ to SQL (DLINQ) |
|
| エンティティ (Entity Framework : EF) を介した、リレーショナル データベース。データ プロバイダが提供されているならば、SQL Server以外にも対応 | LINQ to Entities | |
| メモリ内のXML文書 (XML documents) | LINQ to XML (XLINQ) |
int[] values = { 1, 2, 3, 4, 5 };
IEnumerable<int> query =
from a in values
where a > 3
select a;
foreach (int variable in query)
{
Console.Write(variable); // 4, 5
}
C# の統合言語クエリ (LINQ) | Microsoft Learn
| 句 (clause) | 用途 |
|---|---|
| from | クエリを実行するデータソース。またはローカルの範囲変数 |
| where | 結果のフィルタ |
| select | 結果の型と形状 |
| group | 結果のグループ化 |
| orderby | 結果の並べ替え |
| join | 2つのデータソースを結合 |
| into | select、group、joinの結果を参照するための識別子 |
| let | クエリ式の結果を格納 |
クエリ式はfrom句で始め、groupまたはselect句で終えます。
クエリまたはサブクエリを実行するデータソース、またはソース シーケンスの各要素を表すローカルの範囲変数を指定します。from 句 - C# リファレンス | Microsoft Learn
from 範囲変数 in データソース
データソースはIEnumerable、IEnumerable<T>またはIQueryable<T>の派生型である必要があります。
データソースがList<int>ならば範囲変数 (range variable) はintと推定されますが、ArrayListのような非ジェネリックの型の場合、型を指定してキャストさせる必要があります。LINQ を使用して ArrayList にクエリを実行する方法 (C#) | Microsoft Learn
ArrayList arrayList = new ArrayList { 1, 2, 3 };
IEnumerable<int> query1 =
from num in arrayList // error CS1934: ソース型 'ArrayList' のクエリ パターンの実装が見つかりませんでした。'Select' が見つかりません。範囲変数 'a' の型を明示的に指定してください。
select num;
IEnumerable<int> query2 =
from int num in arrayList // ok
select num;
データソースがIEnumerableのときは、すべての要素がIEnumerable<T>へキャストされた上で処理されます。
どの要素がクエリ式から返されるかを指定します。where 句 - C# リファレンス | Microsoft Learn
| 記述する内容 | 例 |
|---|---|
| 単一の述語 (predicate) を記述 | where num < 5 |
| &&や||演算子を使用して、複数の述語を記述 | where num < 5 && num % 2 == 0 |
| 演算子を省略して、複数の述語を記述 (&&演算子を指定したと見なされる) | where num < 5 where num % 2 == 0 |
| メソッドを記述 | where IsEven(num) |
whereキーワードは、コンパイル時にWhere()メソッドの呼び出しに変換されます。また記述した式は、クエリの結果を要求されたときに評価されます。
クエリが実行されたときに生成される値の、型を指定します。
select 句 - C# リファレンス - C# | Microsoft Learn
int[] values = { 0x61, 0x62, 0x63 };
IEnumerable<char> query =
from num in values
select (char)num;
query.ToArray(); // 'a', 'b', 'c'
string[] words = { "B1", "A1", "A2", "B2" };
IEnumerable<IGrouping<char, string>> query =
from word in words
group word by word[0];
Dictionary<char, int> dic = query.ToDictionary(s => s.Key, s => s.Count());
// {[B, 2]}
// {[A, 2]}
グループに追加の操作をするならば、intoで一時的な識別子を作成しクエリを続け、selectまたは別のgroup句で終了します。
IEnumerable<IGrouping<char, string>> query =
from word in words
group word by word[0] into c
orderby c.Key
select c;
複数のキーで要素をグループ化するには、複合キー (composite keys) を用います。複合キーでグループ化する - group 句 - C# リファレンス - C# | Microsoft Learn
string[] words = { "B1", "A1", "A2", "B2", "B30" };
var query =
from word in words
group word by new { c = word[0], length = word.Length };
var dic = query.ToDictionary(s => s.Key, s => s.Count());
// {[{ c = B, length = 2 }, 2]}
// {[{ c = A, length = 2 }, 2]}
// {[{ c = B, length = 3 }, 1]}
このときの複合キーを匿名型 (anonymous type) ではなく名前付きの型 (named type) とするには、キーとなる構造体を
struct MyStruct
{
public char c;
public int length;
}
のように定義して
IEnumerable<IGrouping<MyStruct, string>> query =
from word in words
group word by new MyStruct { c = word[0], length = word.Length };
のように利用します。このとき構造体ではなくクラスとするには、Equals()とGetHashCode()をオーバーライドして定義します。
class MyClass
{
public char c;
public int length;
public override bool Equals(object obj)
{
MyClass other = (MyClass)obj;
return other.c == this.c && other.length == this.length;
}
public override int GetHashCode()
{
string str = $"{this.c}{this.length}";
return str.GetHashCode();
}
}
ディレクトリ ツリーで重複するファイルを照会する方法 (LINQ) (C#) - C# | Microsoft Learn
返されるシーケンスまたはサブシーケンス (グループ) を、昇順または降順で並べ替えられます。orderby 句 - C# リファレンス | Microsoft Learn
| クエリ構文 | メソッド構文 | 機能 |
|---|---|---|
| orderby | OrderBy() | 要素を、昇順に並べ替える |
| orderby … descending | OrderByDescending() | 要素を、降順に並べ替える |
| orderby …, … | ThenBy() | 後続の要素を、昇順に並べ替える |
| orderby …, … descending | ThenByDescending() | 後続の要素を、降順に並べ替える |
| なし | Reverse() | 要素の順序を反転させる |
string[] words = { "B", "A", "D1", "C1" };
IEnumerable<string> query1 =
from word in words
orderby word.Length
select word;
// "B", "A", "D1", "C1"
IEnumerable<string> query2 =
from word in words
orderby word[0] descending
select word;
// "D1", "C1", "B", "A"
IEnumerable<string> query3 =
from word in words
orderby word.Length, word[0]
select word;
// "A", "B", "C1", "D1"
直接の関連のない異なるソース シーケンスの要素を関連付けられます。join 句 - C# リファレンス | Microsoft Learn
| 結合方法 | 機能 |
|---|---|
| 内部結合 (Inner join) | |
| グループ結合 (Group join) | 結果を配列に格納 |
| 左外部結合 (Left outer join) | 一致する要素がないときに、既定の要素を格納 |
join句の後にintoがなければJoin()に、あればGroupJoin()に変換されます。
LINQではクエリの結果ではなく、クエリを格納する変数をクエリ変数と呼びます。クエリ変数 - クエリ式の基本 (C# での LINQ) | Microsoft Learn
クエリを用いたクエリ構文は、コンパイル時にメソッド構文に変換されます。
| 句 | クエリの例 | 対応するメソッド |
|---|---|---|
| from | from int i in numbers | Cast() |
| from | 複数のfrom句 | SelectMany |
| where | where | Where() |
| select | select | Select() |
| group |
|
GroupBy() |
| orderby | orderby | OrderBy() |
| orderby | orderby … descending | OrderByDescending() |
| orderby | orderby …, … | ThenBy() |
| orderby | orderby …, … descending | ThenByDescending() |
| join | join … in … on … equals … into … | GroupJoin() |
| join | join … in … on … equals … | Join() |
int[] values = { 1, 2, 3, 4, 5 };
// クエリ構文
IEnumerable<int> query1 =
from num in values
where num > 3
select num;
// メソッド構文
IEnumerable<int> query2 =
values.Cast<int>()
.Where(a => a > 3)
.Select(a => a);
Count()やMax()などにはクエリ式の句がないため、メソッドを用いる必要があります。
データを評価するごとに呼び出される式で処理数を計数することで、処理の進捗を示せます。
int count = 0;
IEnumerable<int> source = Enumerable.Range(0, 10);
IEnumerable<int> query = source.Where((x) =>
{
Console.WriteLine(count++); // 処理数を数える
return x % 2 == 0;
});
query.ToArray();