LINQクエリキーワード一覧

クエリ構文で使用するキーワード

以下にクエリ構文で使用できるキーワードを示します。
クエリ構文についてはLINQのクエリ構文を参照してください。

「共用キーワード」はキーワードとセットで使用するキーワードです。
太字の共用キーワードは必ず使用し、それ以外は任意で使用します。

キーワード 役割 共用キーワード
from シーケンスから要素を取り出し範囲変数に格納する in
where Whereメソッドに相当  
select Selectメソッドに相当 into
group GroupByメソッドに相当 by
into
orderby OrderByメソッド
OrderByDescendingメソッド
ThenByメソッド
ThenByDescendingメソッドに相当
ascending
descending
join Joinメソッド
GroupJoinメソッドに相当
in
on
equals
into
into from、group句の後に新たなクエリ式を接続する
join句でGroupJoinメソッドを使用する
 
let クエリ式内で範囲変数を宣言  

from句

クエリ式は必ずfrom句から始まります。
from句はシーケンスから要素をひとつ取り出し、範囲変数に格納します。


IEnumerable<int> query =
    from n in nums
    where n % 2 == 0
    select n;

複数のfrom句

from句は連続して記述することもできます。
この場合、SelectManyメソッドの動作となります。

最初のfrom句で配列などのコレクションやクラス(構造体)が取り出される場合、次のfrom句でそれらから要素やクラスのメンバを取り出すことができます。


List<List<string>> strs = new List<List<string>>()
{
    new List<string>()
    {
        "a", "bb", "ccc"
    },
    new List<string>()
    {
        "d", "ee"
    }
};

//文字数が1より多い文字列を取り出し
IEnumerable<string> query =
    from s1 in strs
    from s2 in s1
    where s2.Length > 1
    select s2;

//以下のメソッド構文と同じ
IEnumerable<string> method =
    strs.SelectMany(s1 => s1, (x, y) => new { x, y })
    .Where(s2 => s2.y.Length > 1)
    .Select(x => x.y);

foreach (var x in query)
    Console.WriteLine("{0} ", x);
bb ccc ee

最初のfrom句で取り出される範囲変数s1は「List<str>」が格納されます。
それを次のfrom句でstring型データを取り出しています。

その他、別のシーケンスをひとつのクエリ式内で同時に使用できます。


List<int> nums = new List<int>()
{
    1, 2
};

List<string> strs = new List<string>()
{
    "aaa", "bbb", "ccc"
};

//numsとstrsを合体させて
//匿名型で返す
var query =
    from n in nums
    from s in strs
    select new { N = n, S = s};

//以下のメソッド構文と同じ
var method =
    nums.SelectMany(
        n => strs,
        (n, s) => new { N = n, S = s });

foreach (var x in query)
    Console.WriteLine("{0} {1} ", x.N, x.S);
1 aaa
1 bbb
1 ccc
2 aaa
2 bbb
2 ccc

where句

where句はメソッド構文のWhereメソッドに該当します。
where句は条件に合うデータを返します。
条件で絞り込む、とも言えます。


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

//偶数のみを取得
IEnumerable<int> query =
    from n in nums
    where n % 2 == 0
    select n;

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

select句

select句はメソッド構文のSelectメソッドに該当します。
select句はデータを加工し最終的な出力を行います。


List<int> nums = new List<int>()
{
    2, 4, 6, 8
};

//要素を二倍にする
IEnumerable<int> query =
    from n in nums
    select n * 2;

foreach (var n in query)
    Console.Write("{0} ", n);
4 8 12 16

select句が出現するとクエリ式は終了します。
select句の後ろに別のクエリ式を続けたい場合はintoを使用します。


List<int> nums = new List<int>()
{
    2, 4, 6, 8
};

//最初のselect句で要素を二倍に
//次のwhere句で値が10以上の要素を取り出し
IEnumerable<int> query =
    from n1 in nums
    select n1 * 2 into n2
    where n2 > 10
    select n2;

foreach (var n in query)
    Console.Write("{0} ", n);
12 16

intoに続く範囲変数n2は、直前のselect句で加工された結果の値が格納されています。

これはつまり以下のメソッド構文と同じになります。
(メソッド構文の場合は最後のSelectメソッドは不要)


IEnumerable<int> query = 
    nums.Select(n1 => n1 * 2)
    .Where(n2 => n2 > 10)
    .Select(n2 => n2);

なお、intoの前と後とでは別のクエリ式なので、範囲変数はそれぞれで独立しています。
上のコードの範囲変数「n1」はintoの後では使えません。
分かりやすくするために別名にしていますが、intoの前後で同じ名前の範囲変数があっても問題ありません。

group句

group句はメソッド構文のGroupByメソッドに該当します。
group句は任意のキーでデータをグループ化します。


class Test
{
    public int Num;
    public string Str;

    public Test(int n, string s)
    {
        Num = n;
        Str = s;
    }
}

static void Main(string[] args)
{
    List<Test> tests = new List<Test>()
    {
        new Test(1, "aaa"),
        new Test(2, "bbb"),
        new Test(3, "ccc"),
        new Test(1, "ddd"),
        new Test(3, "eee"),
    };

    IEnumerable<IGrouping<int, Test>> query =
         from t in tests
         group t by t.Num;

    foreach (var x in query)
    {
        foreach (Test t in x)
            Console.Write("{0}-{1} ", t.Num, t.Str);
        Console.WriteLine();
    }
    
    Console.ReadLine();
}
1-aaa 1-ddd 
2-bbb 
3-ccc 3-eee 

文法は「group グループ化される要素 by キー」の順序となります。

group句が出現するとクエリ式は終了します。
group句の後ろに別のクエリ式を接続するにはintoを使用します。
これはselect句と同様なのでそちらを参照してください。

orderby句

orderby句はメソッド構文のOrderbyOrderByDescendingメソッドに該当します。
orderby句はシーケンスを並べ替えます。


List<int> nums = new List<int>()
{
    3, 5, 14, 11, 2, 19
};

//昇順
IEnumerable<int> query1 =
    from n in nums
    orderby n //ascendingは不要
    select n;

//降順
IEnumerable<int> query2 =
    from n in nums
    orderby n descending
    select n;

foreach (var n in query1)
    Console.Write("{0} ", n);

Console.WriteLine();

foreach (var n in query2)
    Console.Write("{0} ", n);
2 3 5 11 14 19 
19 14 11 5 3 2 

orderby句の並べ替えはデフォルトで昇順なので、ascendingキーワードは付ける必要はありません。
(付けても構いません)

ascending、descendingキーワードに続いてコンマ(,)を書き、さらに要素を指定すると、ThenByThenByDescendingメソッドの動作となります。
これらは並べ替え順序が同じ要素同士を別の条件で並べ替えをします。


class Test
{
    public int Num;
    public string Str;

    public Test(int n, string s)
    {
        Num = n;
        Str = s;
    }
}

static void Main(string[] args)
{
    List<Test> tests = new List<Test>()
    {
        new Test(5, "aaa"),
        new Test(8, "bbb"),
        new Test(2, "ccc"),
        new Test(2, "ddd"),
        new Test(8, "eee")
    };

    //昇順→昇順
    IEnumerable<Test> query1 =
        from t in tests
        orderby t.Num, t.Str
        select t;

    //昇順→降順
    IEnumerable<Test> query2 =
        from t in tests
        orderby t.num, t.str descending
        select t;

    foreach (var t in query1)
        Console.WriteLine("{0} {1}", t.Num, t.Str);

    Console.WriteLine();

    foreach (var t in query2)
        Console.WriteLine("{0} {1}", t.Num, t.Str);

    Console.ReadLine();
}
2 ccc
2 ddd
5 aaa
8 bbb
8 eee

2 ddd
2 ccc
5 aaa
8 eee
8 ddd

join句

join句はメソッド構文のJoinメソッドに該当します。
join句は二つのシーケンスで共通する要素をキーとして結合し、新しいシーケンスを作ります。


//役職
class Position
{
    public int ID;
    public string Name;

    public Position(int id, string name)
    {
        ID = id;
        Name = name;
    }
}

//人物
class Person
{
    public int ID;
    public string Name;
    public int PositionID;

    public Person(int id, string name, int positionID)
    {
        ID = id;
        Name = name;
        PositionID = positionID;
    }
}

static void Main(string[] args)
{
    List<Position> positions = new List<Position>()
    {
        new Position(1, "部長"),
        new Position(2, "課長"),
        new Position(3, "係長"),
        new Position(4, "ヒラ"),
    };

    List<Person> persons = new List<Person>()
    {
        new Person(1, "A山B太", 1),
        new Person(2, "C谷D男", 2),
        new Person(3, "E下F子", 2),
        new Person(4, "G田H雄", 3),
        new Person(5, "I森J美", 3),
        new Person(6, "K川L子", 4),
        new Person(7, "M沢N助", 4),
        new Person(8, "O木P一", 4),
    };

    //匿名型なのでvar
    var query =
        from pos in positions
        join per in persons on pos.ID equals per.PositionID
        select new { PositionName = pos.Name, Name = per.Name };

    foreach (var x in query)
        Console.WriteLine("{0} {1}", x.PositionName, x.Name);

    Console.ReadLine();
}
部長 A山B太
課長 C谷D男
課長 E下F子
係長 G田H雄
係長 I森J美
ヒラ K川L子 
ヒラ M沢N助
ヒラ O木P一

上記の例ではPositionクラスの「ID」フィールドとPersonクラスの「PositionID」フィールドを共通のキーとして、新しい匿名型を作りだしてます。

join句はintoキーワードと共に使用するとGroupJoinメソッドの動作となります。


var query =
    from pos in positions
    join per in persons on pos.ID equals per.PositionID into g
    select new { PositionName = pos.Name, Groups = g };

foreach (var x in query)
{
    Console.Write("{0} ", x.PositionName);
    foreach (Person p in x.Groups)
        Console.Write("{0} ", p.Name);
    Console.WriteLine();
}
部長 A山B太
課長 C谷D男 E下F子
係長 G田H雄 I森J美
ヒラ K川L子 M沢N助 O木P一

「g」にはキーで共通化されたグループ(シーケンス)が格納されます。

let句

let句はクエリ式内で新しい範囲変数の使用を宣言します。
これはクエリ式内で必要な計算等の結果を保存しておくことができます。


List<string> strs = new List<string>()
{
    "This is a sample code of CSharp.",
    "This is a pen.",
    "I am a student boy."
};

//単語数が5つ以上
//かつ「is」が含まれる文を取得
IEnumerable<string> query =
    from str in strs
    let words = str.ToLower().Split(' ')
    where words.Length >= 5 && words.Contains("is")
    select str;

foreach (var x in query)
    Console.WriteLine("{0} ", x);
This is a sample code of CSharp.