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 strs in lstStrs
    from s in strs
    where s.Length > 1
    select s;

//以下のメソッド構文と同じ
IEnumerable<string> method =
    lstStrs.SelectMany(strs => strs)
    .Where(s => s.Length > 1)
    .Select(s => s);

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

最初のfrom句では、List<List<string>>型の値からList<string>型の範囲変数を取り出しています。
そこから次のfrom句でtring型の変数を取り出しています。

別のシーケンスをひとつのクエリ式内で同時に使用できます。
(これもSelectManyメソッドと同様です)


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(
        _ => 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

into演算子

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演算子の前と後とでは別のクエリ式なので、範囲変数はそれぞれで独立しています。
上のコードの範囲変数n1into演算子の後では使えません。
分かりやすくするために別名にしていますが、into演算子の前後で同じ名前の範囲変数があっても問題ありません。

group句

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


class NumStr
{
    public int Num;
    public string Str;

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

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

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

    //以下のメソッド構文と同じ
    IEnumerable<IGrouping<int, NumStr>> method =
        lstNS.GroupBy(ns => ns.Num);

    foreach (IGrouping<int, NumStr> g in query)
    {
        foreach (NumStr ns in g)
            Console.Write("{0}-{1} ", ns.Num, ns.Str);
        Console.WriteLine();
    }

    Console.ReadLine();
}
1-aaa 1-ddd 
2-bbb 
3-ccc 3-eee 

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

group句が出現するとクエリ式は終了します。
group句の後ろに別のクエリ式を接続するにはinto演算子を使用します。

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演算子は付ける必要はありません。
(付けても構いません)

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


class NumStr
{
    public int Num;
    public string Str;

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

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

    //昇順→昇順
    IEnumerable<NumStr> query1 =
        from ns in lstNS
        orderby ns.Num, ns.Str
        select ns;

    //昇順→降順
    IEnumerable<NumStr> query2 =
        from ns in lstNS
        orderby ns.Num, ns.Str descending
        select ns;

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

    Console.WriteLine();

    foreach (NumStr ns in query2)
        Console.WriteLine("{0} {1}", ns.Num, ns.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一

inキーワードで要素を範囲変数に取り出します。
次のonキーワードで連結するキーの指定を行います。
キー同士はequalsキーワードで連結します。

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

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.