Anders Hejlsberg, Mads Torgersen
Intergen
January 2007
日本語版最終更新日 2007 年 7 月 17 日
適用対象 :
Visual Studio 2008
.Net Framework 3.5
概要: 標準クエリ演算子は、.NET の任意の配列またはコレクションにクエリを実行できる API です。標準クエリ演算子 API (Standard Query Operators API) は、System.Query.dll というアセンブリに含まれる、System.Query.Sequence 静的クラスで宣言されたメソッドで構成されます。
目次
技術仕様
シーケンス クラス
制限演算子
プロジェクション演算子
パーティション分割演算子
結合演算子
連結演算子
順序付け演算子
グループ化演算子
セット演算子
変換演算子
等価演算子
要素演算子
生成演算子
限定子
集計演算子
技術仕様
"標準クエリ演算子" は、.NET の任意の配列またはコレクションにクエリを実行できる API です。標準クエリ演算子 API (Standard Query Operators API) は、System.Query.dll というアセンブリに含まれる、System.Query.Sequence 静的クラスで宣言されたメソッドで構成されます。
標準クエリ演算子 API は、.NET 2.0 共通言語仕様 (CLS) に従ってコンパイルされ、ジェネリックをサポートするすべての .NET 言語で使用できます。標準クエリ演算子の使用は必須ではありませんが、使用すれば、拡張メソッド、ラムダ式、およびネイティブ クエリ構文をサポートする言語により、エクスペリエンスが大幅に向上します。今後リリースされる C# 3.0 および Visual Basic 9.0 には、これらの機能を含める予定です。
標準クエリ演算子は、"シーケンス" を操作します。ある型 T に対してインターフェイス IEnumerable<T> を実装するオブジェクトはすべて、その型のシーケンスと見なされます。
この仕様で示している例は、すべて C# 3.0 で記述しており、標準クエリ演算子は using 句を使用してインポートされているものとします。
また、例では次のクラスを参照します。
public class Customer
{
public int CustomerID;
public string Name;
public string Address;
public string City;
public string Region;
public string PostalCode;
public string Country;
public string Phone;
public List<Order> Orders;
}
public class Order
{
public int OrderID;
public int CustomerID;
public Customer Customer;
public DateTime OrderDate;
public decimal Total;
}
public class Product
{
public int ProductID;
public string Name;
public string Category;
public decimal UnitPrice;
public int UnitsInStock;
}
さらに、次の 3 つの変数が存在することを想定します。
List<Customer> customers = GetCustomerList();
List<Order> orders = GetOrderList();
List<Product> products = GetProductList();
Func デリゲート型
System.Query.Func ファミリのジェネリック デリゲート型を使用して、"実行時に" デリゲート型を構築できるため、明示的なデリゲート宣言が必要なくなります。
public delegate TResult Func<TResult>();
public delegate TResult Func<TArg0, TResult>(TArg0 arg0);
public delegate TResult Func<TArg0, TArg1, TResult>(TArg0 arg0, TArg1
arg1);
public delegate TResult Func<TArg0, TArg1, TArg2, TResult>(TArg0 arg0,
TArg1 arg1, TArg2 arg2);
public delegate TResult Func<TArg0, TArg1, TArg2, TArg3, TResult>(TArg0
arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3);
各 Func 型では、TArg0、TArg1、TArg2、および TArg3 の型パラメータが引数型を表し、TResult 型パラメータが結果型を表します。
以下の例では、Customer を受け取り、bool を返す、デリゲート型のローカル変数 predicate を宣言しています。このローカル変数には、指定された顧客がロンドンに在住する場合に TRUE を返す匿名メソッドが代入されます。その後、predicate で参照されるデリゲートを使用して、ロンドン在住のすべての顧客が検索されます。
Func<Customer, bool> predicate = c => c.City == "London";
IEnumerable<Customer> customersInLondon = customers.Where(predicate);
シーケンス クラス
System.Query.Sequence 静的クラスでは、標準クエリ演算子と呼ばれる一連のメソッドが宣言されます。ここでは、これらのメソッドについて説明します。
大多数の標準クエリ演算子は、IEnumerable<T> を拡張する拡張メソッドです。つまり、各メソッドは、IEnumerable<T> を実装する配列やコレクションに対して完全なクエリ言語を形成します。
拡張メソッドの詳細については、C# 3.0 と Visual Basic 9.0 の言語仕様を参照してください。
制限演算子
Where
Where 演算子は、述語を基にシーケンスのフィルタ処理を行います。
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate);
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, int, bool> predicate);
Where 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
Where から返されるオブジェクトを列挙すると、元のシーケンスが列挙され、その中から述語関数が TRUE を返す要素が返されます。述語関数の最初の引数は、テストする要素を表します。2 番目の引数が存在する場合は、元のシーケンス内での要素の位置をゼロ (0) から始まるインデックスで表します。
次の例では、価格が 10 以上の製品のシーケンスが作成されます。
IEnumerable<Product> x = products.Where(p => p.UnitPrice >= 10);
C# 3.0 のクエリ式では、where 句が Where の呼び出しに相当します。上記の例は、次のように変換したコードに等しくなります。
IEnumerable<Product> x =
from p in products
where p.UnitPrice >= 10
select p;
プロジェクション演算子
Select
Select 演算子は、シーケンス上でプロジェクションを実行します。
public static IEnumerable<TResult> Select<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TResult> selector);
public static IEnumerable<TResult> Select<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, int, TResult> selector);
Select 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
Select から返されるオブジェクトを列挙すると、元のシーケンスが列挙され、要素ごとに選択関数の評価結果が返されます。選択関数の最初の引数は、処理する要素を表します。2 番目の引数が存在する場合は、元のシーケンス内での要素の位置をゼロ (0) から始まるインデックスで表します。
次の例では、全製品の名前のシーケンスが作成されます。
IEnumerable<string> productNames = products.Select(p => p.Name);
C# 3.0 のクエリ式では、select 句が Select の呼び出しに相当します。上記の例は、次のように変換したコードに等しくなります。
IEnumerable<string> productNames = from p in products select p.Name;
次の例では、価格が 10 以上の各製品の名前と価格を含むオブジェクトの一覧が作成されます。
var namesAndPrices =
products.
Where(p => p.UnitPrice >= 10).
Select(p => new { p.Name, p.UnitPrice }).
ToList();
次の例では、価格が 10 以上の製品のインデックスのシーケンスが作成されます。
IEnumerable<int> indices =
products.
Select((product, index) => new { product, index }).
Where(x => x.product.UnitPrice >= 10).
Select(x => x.index);
SelectMany
SelectMany 演算子は、シーケンス上で一対多の要素プロジェクションを実行します。
public static IEnumerable<TResult> SelectMany<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, IEnumerable<TResult>> selector);
public static IEnumerable<TResult> SelectMany<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, int, IEnumerable<TResult>> selector);
public static IEnumerable<TResult> SelectMany<TOuter, TInner, TResult>(
this IEnumerable<TOuter> source,
Func<TOuter, IEnumerable<TInner>> selector,
Func<TOuter, TInner, TResult> resultSelector);
public static IEnumerable<TResult> SelectMany<TOuter, TInner, TResult>(
this IEnumerable<TOuter> source,
Func<TOuter, int, IEnumerable<TInner>> selector,
Func<TOuter, TInner, TResult> resultSelector);
SelectMany 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
SelectMany から返されるオブジェクトを列挙すると、selector 関数を使用して各オブジェクトが列挙可能なオブジェクトにマップされ、マップされた列挙可能な各オブジェクトの要素が列挙されます。resultSelector が指定されていない場合は、列挙された各要素が返され、指定されている場合は、列挙された各要素が、対応する元の要素と共に resultSelector に渡され、結果の値が返されます。選択関数の最初の引数は、処理する要素を表します。2 番目の引数が存在する場合は、元のシーケンス内での要素の位置をゼロ (0) から始まるインデックスで表します。
次の例では、デンマーク在住の顧客の注文から成るシーケンスが作成されます。
IEnumerable<Order> orders =
customers.
Where(c => c.Country == "Denmark").
SelectMany(c => c.Orders);
このクエリで SelectMany の代わりに Select が使用されると、結果は IEnumerable<Order> 型ではなく IEnumerable<List<Order>> 型になります。
次の例では、デンマーク在住の顧客から 2005 年に行われた注文の顧客名と注文 ID を含むオブジェクトのシーケンスが作成されます。
var namesAndOrderIDs =
customers.
Where(c => c.Country == "Denmark").
SelectMany(c => c.Orders).
Where(o => o.OrderDate.Year == 2005).
Select(o => new { o.Customer.Name, o.OrderID });
上記の例では、注文を行った顧客の Name プロパティをフェッチするために、Customer プロパティを使用して、"ナビゲーションを戻して" います。注文に Customer プロパティが含まれていない (つまり、リレーションシップが単方向だった) 場合、クエリを次のように書き直し、最後の Select で顧客を参照できるように、現在の顧客 (c) をスコープ内に保持します。
var namesAndOrderIDs =
customers.
Where(c => c.Country == "Denmark").
SelectMany(c => c.Orders, (c,o) => new { c, o }).
Where(co => co.o.OrderDate.Year == 2005).
Select(co => new { co.c.Name, co.o.OrderID });
C# 3.0 のクエリ式では、最初の from 句以外のすべてが SelectMany の呼び出しに相当します。上記の例は、次のように変換したコードに等しくなります。
var namesAndOrderIDs =
from c in customers
where c.Country == "Denmark"
from o in c.Orders
where o.OrderDate.Year == 2005
select new { c.Name, o.OrderID };
パーティション分割演算子
Take
Take 演算子は、シーケンスから指定数の要素を返し、シーケンスの残りの部分をスキップします。
public static IEnumerable<TSource> Take<TSource>(
this IEnumerable<TSource> source,
int count);
Take 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。source 引数が NULL の場合は、ArgumentNullException がスローされます。
Take から返されるオブジェクトを列挙すると、元のシーケンスが列挙され、引数で指定された要素数に達するか、元のシーケンスの末尾に達するまで、要素が返されます。count 引数がゼロ (0) 以下の場合は、元のシーケンスは列挙されず、要素は返されません。
Take 演算子と Skip 演算子の機能には相互補完の関係があります。シーケンス s があるとします。この場合に s.Take(n) と s.Skip(n) を連結すると、元と同じ s がシーケンスとして返されます。
次の例では、価格の高い方から 10 製品のシーケンスが作成されます。
IEnumerable<Product> MostExpensive10 =
products.OrderByDescending(p => p.UnitPrice).Take(10);
Skip
Skip 演算子は、シーケンスから指定数の要素をスキップし、シーケンスの残りの部分から成るシーケンスを返します。
public static IEnumerable<TSource> Skip<TSource>(
this IEnumerable<TSource> source,
int count);
Skip 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。source 引数が NULL の場合は、ArgumentNullException がスローされます。
Skip から返されるオブジェクトを列挙すると、元のシーケンスが列挙され、count 引数で指定された数の要素をスキップして、残りの要素が返されます。元のシーケンスに含まれる要素の数が count 引数で指定された数よりも少ない場合は、何も返されません。count 引数がゼロ (0) 以下の場合は、元のシーケンスの全要素から成るシーケンスが返されます。
Take 演算子と Skip 演算子の機能には相互補完の関係があります。シーケンス s があるとします。この場合に s.Take(n) と s.Skip(n) を連結すると、元と同じ s がシーケンスとして返されます。
次の例では、価格の高い 10 製品を除くシーケンスが作成されます。
IEnumerable<Product> AllButMostExpensive10 =
products.OrderByDescending(p => p.UnitPrice).Skip(10);
TakeWhile
TakeWhile 演算子は、テスト結果が TRUE を返す間シーケンスから要素を返し、シーケンスの残りの部分をスキップします。
public static IEnumerable<TSource> TakeWhile<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate);
public static IEnumerable<TSource> TakeWhile<TSource>(
this IEnumerable<TSource> source,
Func<TSource, int, bool> predicate);
TakeWhile 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
TakeWhile から返されるオブジェクトを列挙すると、元のシーケンスが列挙され、述語関数を使用して各要素がテストされて、結果が TRUE だった要素が返されます。述語関数が FALSE を返した時点、または元のシーケンスの末尾に達した時点で、列挙が停止します。述語関数の最初の引数は、テストする要素を表します。2 番目の引数が存在する場合は、元のシーケンス内での要素の位置をゼロ (0) から始まるインデックスで表します。
TakeWhile 演算子と SkipWhile 演算子の機能には相互補完の関係があります。シーケンス s と純粋関数 p があるとします。この場合に s.TakeWhile(p) と s.SkipWhile(p) を連結すると、元と同じ s がシーケンスとして返されます。
SkipWhile
SkipWhile 演算子は、テスト結果が TRUE を返す間シーケンスから要素をスキップし、シーケンスの残りの部分から成るシーケンスを返します。
public static IEnumerable<TSource> SkipWhile<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate);
public static IEnumerable<TSource> SkipWhile<TSource>(
this IEnumerable<TSource> source,
Func<TSource, int, bool> predicate);
SkipWhile 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
SkipWhile から返されるオブジェクトを列挙すると、元のシーケンスが列挙され、述語関数を使用して各要素がテストされて、結果が TRUE だった要素がスキップされます。ある要素で述語関数が FALSE を返した時点で、その要素以降の残りの要素が返されます。このとき、以降の要素では述語関数は呼び出されません。シーケンス内のすべての要素で述語関数が TRUE を返す場合、要素は返されません。述語関数の最初の引数は、テストする要素を表します。2 番目の引数が存在する場合は、元のシーケンス内での要素の位置をゼロ (0) から始まるインデックスで表します。
TakeWhile 演算子と SkipWhile 演算子の機能には相互補完の関係があります。シーケンス s と純粋関数 p があるとします。この場合に s.TakeWhile(p) と s.SkipWhile(p) を連結すると、元と同じ s がシーケンスとして返されます。
結合演算子
Join
Join 演算子は、要素から抽出されたキーの照合結果に基づき、2 つのシーケンスの内部結合を実行します。
public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
this IEnumerable<TOuter> outer,
IEnumerable<TInner> inner,
Func<TOuter, TKey> outerKeySelector,
Func<TInner, TKey> innerKeySelector,
Func<TOuter, TInner, TResult> resultSelector);
public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
this IEnumerable<TOuter> outer,
IEnumerable<TInner> inner,
Func<TOuter, TKey> outerKeySelector,
Func<TInner, TKey> innerKeySelector,
Func<TOuter, TInner, TResult> resultSelector,
IEqualityComparer<TKey> comparer);
Join 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
outerKeySelector 引数と innerKeySelector 引数は、それぞれ outer シーケンスと inner シーケンスの要素から結合キー値を抽出する関数を指定します。resultSelector 引数は、outer シーケンスと inner シーケンスの 2 つの要素を照合した結果の要素を作成する関数を指定します。
Join から返されるオブジェクトを列挙すると、まず、inner シーケンスが列挙され、inner の要素ごとに innerKeySelector 関数が評価され、そのキーによって要素がハッシュ テーブルに収集されます。inner シーケンスのすべての要素とキーが収集されると、outer シーケンスが列挙されます。outer シーケンスの要素ごとに outerKeySelector 関数が評価されます。評価結果が NULL 以外の場合は、結果のキーを使用して、ハッシュ テーブル内の inner シーケンスの対応する要素と照合されます。inner シーケンスの各要素 (存在する場合) との照合では、outer シーケンスの要素と inner シーケンスの要素のペアに対して resultSelector 関数が評価され、評価結果に応じてオブジェクトが返されます。
comparer 引数に NULL 以外の値が指定されると、ハッシュを使用してキーを比較します。それ以外の場合は、既定の等値比較子 EqualityComparer<TKey>.Default が使用されます。
Join 演算子では、outer シーケンスの要素の順序が保持され、outer シーケンスの要素ごとに、対応する inner シーケンスの要素の順序が保持されます。
リレーショナル データベースの用語で言えば、Join 演算子は内部等値結合を実装します。左外部結合や右外部結合など、その他の結合演算専用の標準クエリ演算子はなく、これらは GroupJoin 演算子の機能のサブセットになります。
次の例では、顧客と注文が顧客 ID プロパティで結合され、顧客名、注文日付、および注文合計の組から成るシーケンスが作成されます。
var custOrders =
customers.
Join(orders, c => c.CustomerID, o => o.CustomerID,
(c, o) => new { c.Name, o.OrderDate, o.Total }
);
C# 3.0 のクエリ式では、join 句が Join の呼び出しに相当します。上記の例は、次のように変換したコードに等しくなります。
var custOrders =
from c in customers
join o in orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total };
GroupJoin
GroupJoin 演算子は、要素から抽出されたキーの照合結果に基づき、2 つのシーケンスのグループ結合を実行します。
public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey,
TResult>(
this IEnumerable<TOuter> outer,
IEnumerable<TInner> inner,
Func<TOuter, TKey> outerKeySelector,
Func<TInner, TKey> innerKeySelector,
Func<TOuter, IEnumerable<TInner>, TResult> resultSelector);
public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey,
TResult>(
this IEnumerable<TOuter> outer,
IEnumerable<TInner> inner,
Func<TOuter, TKey> outerKeySelector,
Func<TInner, TKey> innerKeySelector,
Func<TOuter, IEnumerable<TInner>, TResult> resultSelector,
IEqualityComparer<TKey> comparer);
GroupJoin 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
outerKeySelector 引数と innerKeySelector 引数は、それぞれ outer シーケンスと inner シーケンスの要素から結合キー値を抽出する関数を指定します。resultSelector 引数は、outer シーケンスの要素と、それに対応する inner シーケンスの要素から成る要素を作成する関数を指定します。
GroupJoin から返されるオブジェクトを列挙すると、まず、inner シーケンスが列挙され、inner の要素ごとに innerKeySelector 関数が評価され、そのキーによって要素がハッシュ テーブルに収集されます。inner シーケンスのすべての要素とキーが収集されると、outer シーケンスが列挙されます。outer シーケンスの要素ごとに outerKeySelector 関数が評価されます。その結果のキーを使用して、ハッシュ テーブル内の inner シーケンスの対応する要素と照合されます。次に、outer シーケンスの要素と、inner シーケンスの対応する要素のシーケンス (空になることもあります) に対して resultSelector 関数が評価され、評価結果のオブジェクトが返されます。
comparer 引数に NULL 以外の値が指定されると、ハッシュを使用してキーを比較します。それ以外の場合は、既定の等値比較子 EqualityComparer<TKey>.Default が使用されます。
GroupJoin 演算子では、outer シーケンスの要素の順序が保持され、outer シーケンスの要素ごとに、対応する inner シーケンスの要素の順序が保持されます。
GroupJoin 演算子は (outer シーケンスの要素と、inner シーケンスの対応する要素のシーケンスが対になった) 階層型の結果を作成します。従来のリレーショナル データベースには直接対応する用語はありません。
次の例では、顧客と注文のグループ結合が行われ、顧客名とその顧客が行った注文の総合計の組から成るシーケンスが作成されます。
var custTotalOrders =
customers.
GroupJoin(orders, c => c.CustomerID, o => o.CustomerID,
(c, co) => new { c.Name, TotalOrders = co.Sum(o => o.Total) }
);
C# 3.0 のクエリ式では、join...into 句が GroupJoin の呼び出しに相当します。上記の例は、次のように変換したコードと等しくなります。
var custTotalOrders =
from c in customers
join o in orders on c.CustomerID equals o.CustomerID into co
select new { c.Name, TotalOrders = co.Sum(o => o.Total) };
GroupJoin 演算子は、内部結合と左外部結合のスーパーセットを実装します。内部結合と左外部結合は、どちらもグループ結合を応用して記述できます。たとえば、次の内部結合を考えます。
var custTotalOrders =
from c in customers
join o in orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total };
この内部結合は、次のようにグループ化された注文の繰り返しを後に続けて、グループ結合として記述できます。
var custTotalOrders =
from c in customers
join o in orders on c.CustomerID equals o.CustomerID into co
from o in co
select new { c.Name, o.OrderDate, o.Total };
グループ化された注文に DefaultIfEmpty 演算子を適用することによって、このクエリを左外部結合に変換できます。
var custTotalOrders =
from c in customers
join o in orders on c.CustomerID equals o.CustomerID into co
from o in co.DefaultIfEmpty(emptyOrder)
select new { c.Name, o.OrderDate, o.Total };
ここで emptyOrder は、注文が見つからなかったことを表す Order のインスタンスです。
連結演算子
Concat
Concat 演算子は、2 つのシーケンスを連結します。
public static IEnumerable<TSource> Concat<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second);
Concat 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
Concat から返されるオブジェクトを列挙すると、最初のシーケンスが列挙されて各要素が返され、次に2 番目のシーケンスが列挙されて各要素が返されます。
次の例では、全顧客の住所から、重複していない場所がすべて抽出されます。
IEnumerable<string> locations =
customers.Select(c => c.City).
Concat(customers.Select(c => c.Region)).
Concat(customers.Select(c => c.Country)).
Distinct();
シーケンスを連結するもう 1 つの方法は、(シーケンスの配列のような) シーケンスのシーケンスを構築し、ID 選択関数を指定した SelectMany 演算子を適用する方法です。以下に例を示します。
IEnumerable<string> locations =
new[] {
customers.Select(c => c.City),
customers.Select(c => c.Region),
customers.Select(c => c.Country),
}.
SelectMany(s => s).
Distinct();
順序付け演算子
OrderBy と ThenBy
OrderBy/ThenBy ファミリの演算子は、1 つ以上のキーに従ってシーケンスの順序を設定します。
public static OrderedSequence<TSource> OrderBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector);
public static OrderedSequence<TSource> OrderBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
IComparer<TKey> comparer);
public static OrderedSequence<TSource> OrderByDescending<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector);
public static OrderedSequence<TSource> OrderByDescending<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
IComparer<TKey> comparer);
public static OrderedSequence<TSource> ThenBy<TSource, TKey>(
this OrderedSequence<TSource> source,
Func<TSource, TKey> keySelector);
public static OrderedSequence<TSource> ThenBy<TSource, TKey>(
this OrderedSequence<TSource> source,
Func<TSource, TKey> keySelector,
IComparer<TKey> comparer);
public static OrderedSequence<TSource> ThenByDescending<TSource, TKey>(
this OrderedSequence<TSource> source,
Func<TSource, TKey> keySelector);
public static OrderedSequence<TSource> ThenByDescending<TSource, TKey>(
this OrderedSequence<TSource> source,
Func<TSource, TKey> keySelector,
IComparer<TKey> comparer);
OrderBy、OrderByDescending、ThenBy、および ThenByDescending の各演算子は、複数のキーによってシーケンスの順序を設定するために組み合わせることができる、演算子のファミリを形成します。演算子は、次の形式で組み立てます。
source .OrderBy(...) .ThenBy(...) .ThenBy(...) ...
ここで OrderBy(...) は OrderBy または OrderByDescending の呼び出しで、ThenBy(...) (存在する場合) は、ThenBy または ThenByDescending の呼び出しです。最初の OrderBy または OrderByDescending により第 1 の順序が設定され、最初の ThenBy または ThenByDescending により第 2 の順序が設定され、2 番目の ThenBy または ThenByDescending により第 3 の順序が設定されます。以下同様です。各順序は、次の要素によって定義されます。
-
TSource 型の要素から、TKey 型のキー値を抽出する keySelector 関数。
- キー値を比較するための省略可能な comparer。comparer が指定されていないか、comparer 引数が null の場合、既定の comparer Comparer<TKey>.Default が使用されます。
- 並べ替え方向。OrderBy メソッドと ThenBy メソッドは昇順に並べ替え、OrderByDescending メソッドと ThenByDescending メソッドは降順に並べ替えます。
OrderBy、OrderByDescending、ThenBy、または ThenByDescending の呼び出しは、演算子に渡された複数の引数に対応する、OrderedSequence<TSource> 型の列挙可能なオブジェクトを割り当てて返します。source 引数または keySelector 引数が NULL の場合は、ArgumentNullException がスローされます。OrderedSequence<TElement> クラスは IEnumerable<TElement> を実装しますが、それ以外にパブリック メンバは導入されません。
これらの演算子の 1 つから返されるオブジェクトを列挙すると、まず、 source が列挙され、全要素が収集されます。次に、収集した要素ごとに keySelector 関数が評価され、順序設定に使用するキーが収集されます。続いて、収集したキー値と順序付けの特性に応じて要素が並べ替えられます。最後に、並べ替えられた順序で要素が返されます。
OrderBy/ThenBy 演算子の結果に対して OrderBy または OrderByDescending を呼び出すと、以前に行われた順序設定とは無関係に、第 1 の順序付けが新たに行われます。
OrderBy/ThenBy 演算子では、安定した並べ替えが行われます。つまり、2 つの要素のキー値が等しい場合、その要素の順序が保持されます。これに対し、不安定な並べ替えでは、キー値が等しい場合の要素の順序は保持されません。
次の例では、カテゴリ順に並べ替えられ、次に価格の降順に並べ替えられてから、名前順に並べ替えられた全製品のシーケンスが作成されます。
IEnumerable<Product> orderedProducts1 =
products.
OrderBy(p => p.Category).
ThenByDescending(p => p.UnitPrice).
ThenBy(p => p.Name);
C# 3.0 のクエリ式では、orderby 句が OrderBy、OrderByDescending、ThenBy、および ThenByDescending に相当します。上記の例は、次のように変換したコードに等しくなります。
IEnumerable<Product> orderedProducts1 =
from p in products
orderby p.Category, p.UnitPrice descending, p.Name
select p;
次の例では、大文字小文字を区別しないで名前順に並べ替えられた、全飲料製品のシーケンスが作成されます。
IEnumerable<Product> orderedProducts2 =
products.
Where(p => p.Category == "Beverages").
OrderBy(p => p.Name, StringComparer.CurrentCultureIgnoreCase);
要素自体の値でシーケンスの順序を設定するには、ID キー選択関数として x => x を指定します。以下に例を示します。
IEnumerable<string> orderedProductNames =
products.
Where(p => p.Category == "Beverages").
Select(p => p.Name).
OrderBy(x => x);
Reverse
Reverse 演算子は、シーケンスの要素を反転します。
public static IEnumerable<TSource> Reverse<TSource>(
this IEnumerable<TSource> source);
Reverse 演算子は、source 引数に対応する、列挙可能なオブジェクトを割り当てて返します。source 引数が NULL の場合は、ArgumentNullException がスローされます。
Reverse から返されるオブジェクトを列挙すると、元のシーケンスが列挙され、全要素が収集されてから、元のシーケンスを逆順に並べ替えた要素が返されます。
グループ化演算子
GroupBy
GroupBy 演算子は、シーケンスの要素をグループ化します。
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource,
TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector);
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource,
TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
IEqualityComparer<TKey> comparer);
public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource,
TKey, TElement>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector);
public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource,
TKey, TElement>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
IEqualityComparer<TKey> comparer);
public interface IGrouping<TKey, TElement> : IEnumerable<TElement>
{
TKey Key { get; }
}
GroupBy 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。comparer 引数は指定されても NULL になることがあります。その他のいずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
keySelector 引数は、元の要素からキー値を抽出する関数を指定します。elementSelector 引数を指定する場合は、元の要素から対象の要素にマップする関数を指定します。elementSelector 引数を指定しないと、元の要素が対象の要素になります。
GroupBy から返されるオブジェクトを列挙すると、元のシーケンスが列挙され、元の要素ごとに keySelector 関数と elementSelector 関数 (存在する場合) が評価されます。すべてのキーと対象要素のペアが収集されたら、IGrouping<TKey, TElement> のインスタンスのシーケンスが返されます。IGrouping<TKey, TElement> の各インスタンスは、特定のキー値を持つ対象要素のシーケンスを表します。グループ化は、キー値が元のシーケンスに最初に出現した順序で行われるため、グループ内の対象要素は、元の要素が元のシーケンスに出現する順序で返されます。グループ化を行うときに、指定された comparer を使用してキー値が比較されます。comparer に NULL が指定された場合は、既定の等値比較子 EqualityComparer<TKey>.Default が使用されます。
次の例では、全製品がカテゴリ別にグループ化されます。
IEnumerable<IGrouping<string, Product>> productsByCategory =
products.GroupBy(p => p.Category);
次の例では、全製品名が製品カテゴリ別にグループ化されます。
IEnumerable<IGrouping<string, string>> productNamesByCategory =
products.GroupBy(p => p.Category, p => p.Name);
C# 3.0 のクエリ式では、group...by 句が GroupBy の呼び出しに相当します。上記の例は、次のように変換したコードに等しくなります。
IEnumerable<IGrouping<string, string>> productNamesByCategory =
from p in products
group p.Name by p.Category;
要素とキー選択の表記は、GroupBy 演算子とは逆順になることに注意してください。
セット演算子
Distinct
Distinct 演算子は、シーケンスから重複する要素を取り除きます。
public static IEnumerable<TSource> Distinct<TSource>(
this IEnumerable<TSource> source);
public static IEnumerable<TSource> Distinct<TSource>(
this IEnumerable<TSource> source,
IEqualityComparer<TSource> comparer);
Distinct 演算子は、source 引数に対応する、列挙可能なオブジェクトを割り当てて返します。source 引数が NULL の場合は、ArgumentNullException がスローされます。
Distinct から返されるオブジェクトを列挙すると、元のシーケンスが列挙され、以前に返されていない各要素が返されます。comparer 引数に NULL 以外を指定した場合は、指定した比較子を使用して要素が比較されます。それ以外の場合は、既定の等値比較子 EqualityComparer<TSource>.Default が使用されます。
次の例では、全製品カテゴリのシーケンスが作成されます。
IEnumerable<string> productCategories =
products.Select(p => p.Category).Distinct();
Union
Union 演算子は、2 つのシーケンスの和集合 (ユニオン) を作成します。
public static IEnumerable<TSource> Union<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second);
public static IEnumerable<TSource> Union<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer);
Union 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
Union から返されるオブジェクトを列挙すると、最初のシーケンスと 2 番目のシーケンスが列挙され、以前に返されていない各要素が返されます。comparer 引数に NULL 以外を指定した場合は、指定した比較子を使用して要素が比較されます。それ以外の場合は、既定の等値比較子 EqualityComparer<TSource>.Default が使用されます。
Intersect
Intersect 演算子は、2 つのシーケンスの積集合を作成します。
public static IEnumerable<TSource> Intersect<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second);
public static IEnumerable<TSource> Intersect<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer);
Intersect 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
Intersect から返されるオブジェクトを列挙すると、最初のシーケンスが列挙され、そのシーケンスの重複しない要素がすべて収集されます。次に、2 番目のシーケンスが列挙され、両方のシーケンスに出現する要素にマークを付けます。最後に、マークが付けられた要素が収集された順番に返されます。comparer 引数に NULL 以外を指定した場合は、指定した比較子を使用して要素が比較されます。それ以外の場合は、既定の等値比較子 EqualityComparer<TSource>.Default が使用されます。
Except
Except 演算子は、2 つのシーケンスの差集合を作成します。
public static IEnumerable<TSource> Except<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second);
public static IEnumerable<TSource> Except<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer);
Except 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
Except から返されるオブジェクトを列挙すると、最初のシーケンスが列挙され、そのシーケンスの重複しない要素がすべて収集されます。次に、2 番目のシーケンスが列挙され、最初のシーケンスにも含まれる要素が削除されます。最後に、残った要素が収集された順番に返されます。comparer 引数に NULL 以外を指定した場合は、指定した比較子を使用して要素が比較されます。それ以外の場合は、既定の等値比較子 EqualityComparer<TSource>.Default が使用されます。
変換演算子
AsEnumerable
AsEnumerable 演算子は、引数を IEnumerable<TSource> 型に変換して返します。
public static IEnumerable<TSource> AsEnumerable<TSource>(
this IEnumerable<TSource> source);
AsEnumerable 演算子は、単に source 引数を返します。この演算子は、source 引数の型をコンパイル時に IEnumerable<TSource> に変更する以外には影響がありません。
コレクションが IEnumerable<T> を実装し、異なるセットのパブリック クエリ演算子も実装している場合に、クエリ演算子のどの実装を使用するかを AsEnumerable 演算子を使用して選択できます。たとえば、クラス Table<T> が IEnumerable<T> を実装し、独自に Where、Select、SelectMany なども実装しているとします。この場合に、次のクエリを考えます。
Table<Customer> custTable = GetCustomersTable();
var query = custTable.Where(c => IsGoodCustomer(c));
この場合は、Table<T> のパブリック演算子 Where が呼び出されます。データベース テーブルを表す Table<T> 型の Where 演算子は、おそらく、リモート実行用に式のツリーを述語引数として受け取り、ツリーを SQL に変換します。たとえば、述語からローカル メソッドを呼び出すためリモート実行を希望しない場合などは、次のように AsEnumerable 演算子を使用して、Table<T> の演算子を隠ぺいし、代わりに標準クエリ演算子を使用可能にすることができます。
Table<Customer> custTable = GetCustomersTable();
var query = custTable.AsEnumerable().Where(c => IsGoodCustomer(c));
これにより、クエリはローカルに実行されることになります。
ToArray
ToArray 演算子は、シーケンスから配列を作成します。
public static TSource[] ToArray<TSource>(
this IEnumerable<TSource> source);
ToArray 演算子は、source シーケンスを列挙し、そのシーケンスの要素を含む配列を返します。source 引数が NULL の場合は、ArgumentNullException がスローされます。
次の例では、顧客がいる地域すべての名前から成る配列が作成されます。
string[] customerCountries =
customers.Select(c => c.Country).Distinct().ToArray();
ToList
ToList 演算子は、シーケンスから List<TSource> を作成します。
public static List<TSource> ToList<TSource>(
this IEnumerable<TSource> source);
ToList 演算子は、source シーケンスを列挙し、そのシーケンスの要素を含む List<TSource> を返します。source 引数が NULL の場合は、ArgumentNullException がスローされます。
次の例では、2005 年に注文を行った顧客を含む List<Customer> が作成されます。
List<Customer> customersWithOrdersIn2005 =
customers.
Where(c => c.Orders.Any(o => o.OrderDate.Year == 2005)).
ToList();
ToDictionary
ToDictionary 演算子は、シーケンスから Dictionary<TKey,TElement> を作成します。
public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector);
public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
IEqualityComparer<TKey> comparer);
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey,
TElement>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector);
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey,
TElement>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
IEqualityComparer<TKey> comparer);
ToDictionary 演算子は source シーケンスを列挙し、要素のキーと値を作成するために、要素ごとに keySelector 関数と elementSelector 関数を評価します。作成されたキーと値のペアは、Dictionary<TKey,TElement> に返されます。elementSelector を指定しなかった場合、各要素の値は単純に要素自体になります。source、keySelector、elementSelector のいずれかの引数が NULL の場合、または keySelector によって作成されたキー値が NULL の場合は、ArgumentNullException がスローされます。keySelector が 2 つの要素に重複するキー値を作成した場合は、ArgumentException がスローされます。結果の辞書では、指定された comparer を使用してキー値が比較されます。comparer に NULL が指定された場合は、既定の等値比較子 EqualityComparer<TKey>.Default が使用されます。
次の例では、2005 年に行われたすべての注文について、注文 ID と注文を対応付ける Dictionary<int,Order> が作成されます。
Dictionary<int,Order> orders =
customers.
SelectMany(c => c.Orders).
Where(o => o.OrderDate.Year == 2005).
ToDictionary(o => o.OrderID);
次の例では、カテゴリ名とそのカテゴリの中で最も高い製品価格を対応付ける Dictionary<string,decimal> が作成されます。
Dictionary<string,decimal> categoryMaxPrice =
products.
GroupBy(p => p.Category).
ToDictionary(g => g.Key, g => g.Group.Max(p => p.UnitPrice));
ToLookup
ToLookup 演算子は、シーケンスから Lookup<TKey, TElement> を作成します。
public static Lookup<TKey, TSource> ToLookup<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector);
public static Lookup<TKey, TSource> ToLookup<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
IEqualityComparer<TKey> comparer);
public static Lookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector);
public static Lookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
IEqualityComparer<TKey> comparer);
public class Lookup<TKey, TElement> : IEnumerable<IGrouping<TKey,
TElement>>
{
public int Count { get; }
public IEnumerable<TElement> this[TKey key] { get; }
public bool Contains(TKey key);
public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator();
}
Lookup<TKey, TElement> は、キーと値のシーケンスを対応付ける、一対多の辞書を実装します。Dictionary<TKey, TElement> はこれとは異なり、キーと単一値を対応付ける、一対一の辞書を実装します。Lookup<TKey, TElement> によって提供される機能は、Join 演算子、GroupJoin 演算子、および GroupBy 演算子の実装に使用されます。
ToLookup 演算子は source シーケンスを列挙し、要素のキーと値を作成するために、要素ごとに keySelector 関数と elementSelector 関数を評価します。作成されたキーと値のペアは、Lookup<TKey, TElement> に返されます。elementSelector を指定しなかった場合、各要素の値は単純に要素自体になります。source、keySelector、elementSelector のいずれかの引数が NULL の場合は、ArgumentNullException がスローされます。Lookup<TKey, TElement> を作成するときに、指定された comparer を使用してキー値が比較されます。comparer に NULL が指定された場合は、既定の等値比較子 EqualityComparer<TKey>.Default が使用されます。
次の例では、カテゴリ名とそのカテゴリ内の製品のシーケンスを対応付ける Lookup<string, Product> が作成されます。
Lookup<string,Product> productsByCategory =
products.ToLookup(p => p.Category);
IEnumerable<Product> beverages = productsByCategory["Beverage"];
OfType
OfType 演算子は、シーケンスの要素を型に基づいてフィルタ選択します。
public static IEnumerable<TResult> OfType<TResult>(
this IEnumerable source);
OfType 演算子は、source 引数に対応する、列挙可能なオブジェクトを割り当てて返します。source 引数が NULL の場合は、ArgumentNullException がスローされます。
OfType から返されるオブジェクトを列挙すると、元のシーケンスが列挙され、シーケンスの要素の中から型 TResult の要素が返されます。具体的には、(TResult)e を評価することにより、"e が TResult である" と評価される各要素 e が返されます。
クラス Person から継承されるクラス Employee があるとすると、次の例では persons のリストから全従業員が返されます。
List<Person> persons = GetListOfPersons();
IEnumerable<Employee> employees = persons.OfType<Employee>();
Cast
Cast 演算子は、シーケンスの要素を指定した型にキャストします。
public static IEnumerable<TResult> Cast<TResult>(
this IEnumerable source);
Cast 演算子は、source 引数に対応する、列挙可能なオブジェクトを割り当てて返します。source 引数が NULL の場合は、ArgumentNullException がスローされます。
Cast から返されるオブジェクトを列挙すると、元のシーケンスが列挙され、型 TResult にキャストされた各要素が返されます。シーケンス内の要素を型 TResult にキャストできない場合は、InvalidCastException がスローされます。
Cast 演算子は、ジェネリック以外のコレクションと標準クエリ演算子との間のブリッジに使用できます。たとえば、ジェネリックではない ArrayList には IEnumerable<TResult> が実装されませんが、次のように Cast 演算子を使用して、不足している型情報を提供できます。
ArrayList objects = GetOrders();
IEnumerable<Order> ordersIn2005 =
objects.
Cast<Order>().
Where(o => o.OrderDate.Year == 2005);
C# 3.0 のクエリ式では、明示的に型指定された繰り返し変数が Cast の呼び出しに相当します。上記の例は、次のように変換したコードと等しくなります。
ArrayList objects = GetOrders();
IEnumerable<Order> ordersIn2005 =
from Order o in objects
where o.OrderDate.Year == 2005
select o;
等価演算子
SequenceEqual
SequenceEqual 演算子は、2 つのシーケンスが等しいかどうかをチェックします。
public static bool SequenceEqual<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second);
public static bool SequenceEqual<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer);
SequenceEqual 演算子は、2 つのシーケンスを並列に列挙し、対応する要素を比較します。comparer 引数に NULL 以外を指定した場合は、指定した比較子を使用して要素が比較されます。それ以外の場合は、既定の等値比較子 EqualityComparer<TSource>.Default が使用されます。対応するすべての要素の比較結果が等しく、2 つのシーケンスの長さが等しい場合に TRUE を返します。それ以外の場合は FALSE を返します。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
要素演算子
First
First 演算子は、シーケンスの先頭要素を返します。
public static TSource First<TSource>(
this IEnumerable<TSource> source);
public static TSource First<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate);
First 演算子は、元のシーケンスを列挙し、述語関数が TRUE を返す最初の要素を返します。述語関数を指定していない場合、First 演算子は単純にシーケンスの先頭要素を返します。
いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。述語関数に一致する要素がない場合、または元のシーケンスが空の場合、InvalidOperationException がスローされます。
次の例では、指定された電話番号を持つ最初の顧客が返されます。
string phone = "206-555-1212";
Customer c = customers.First(c => c.Phone == phone);
上記の例で、指定した電話番号を持つ顧客が存在しない場合は例外がスローされます。要素が見つからなかった場合に既定値を返すようにするには、FirstOrDefault 演算子を使用します。
FirstOrDefault
FirstOrDefault 演算子は、シーケンスの先頭要素を返しますが、要素が見つからなかった場合は既定値を返します。
public static TSource FirstOrDefault<TSource>(
this IEnumerable<TSource> source);
public static TSource FirstOrDefault<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate);
FirstOrDefault 演算子は、元のシーケンスを列挙し、述語関数が TRUE を返す最初の要素を返します。述語関数を指定していない場合、FirstOrDefault 演算子は単純にシーケンスの先頭要素を返します。
いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。述語関数に一致する要素がない場合、または元のシーケンスが空の場合は、default(TSource) を返します。参照型および NULL 値を許容する型の既定値は NULL です。
Last
Last 演算子は、シーケンスの末尾要素を返します。
public static TSource Last<TSource>(
this IEnumerable<TSource> source);
public static TSource Last<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate);
Last 演算子は、元のシーケンスを列挙し、述語関数が TRUE を返す最後の要素を返します。述語関数を指定していない場合、Last 演算子は単純にシーケンスの末尾要素を返します。
いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。述語関数に一致する要素がない場合、または元のシーケンスが空の場合、InvalidOperationException がスローされます。
LastOrDefault
LastOrDefault 演算子は、シーケンスの末尾要素を返しますが、要素が見つからなかった場合は既定値を返します。
public static TSource LastOrDefault<TSource>(
this IEnumerable<TSource> source);
public static TSource LastOrDefault<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate);
LastOrDefault 演算子は、元のシーケンスを列挙し、述語関数が TRUE を返す最後の要素を返します。述語関数を指定していない場合、LastOrDefault 演算子は単純にシーケンスの末尾要素を返します。
いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。述語関数に一致する要素がない場合、または元のシーケンスが空の場合は、default(TSource) を返します。参照型および NULL 値を許容する型の既定値は NULL です。
Single
Single 演算子は、シーケンスの単一要素を返します。
public static TSource Single<TSource>(
this IEnumerable<TSource> source);
public static TSource Single<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate);
Single 演算子は、元のシーケンスを列挙し、述語関数が TRUE を返す単一要素を返します。述語関数を指定していない場合、Single 演算子は単純にシーケンスの単一要素を返します。
いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。元のシーケンスに一致する要素が含まれていない場合、または一致する要素が複数含まれている場合は、InvalidOperationException がスローされます。
次の例では、指定された顧客 ID を持つ 1 人の顧客が返されます。
int id = 12345;
Customer c = customers.Single(c => c.CustomerID == id);
上記の例で、指定した ID を持つ顧客が存在しない場合、または複数存在する場合は例外がスローされます。要素が見つからなかった場合に NULL を返すようにするには、SingleOrDefault 演算子を使用します。
SingleOrDefault
SingleOrDefault 演算子は、シーケンスの単一要素を返しますが、要素が見つからなかった場合は既定値を返します。
public static TSource SingleOrDefault<TSource>(
this IEnumerable<TSource> source);
public static TSource SingleOrDefault<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate);
SingleOrDefault 演算子は、元のシーケンスを列挙し、述語関数が TRUE を返す単一要素を返します。述語関数を指定していない場合、SingleOrDefault 演算子は単純にシーケンスの単一要素を返します。
いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。元のシーケンスに一致する要素が複数含まれる場合は、InvalidOperationException がスローされます。述語関数に一致する要素がない場合、または元のシーケンスが空の場合は、default(TSource) を返します。参照型および NULL 値を許容する型の既定値は NULL です。
ElementAt
ElementAt 演算子は、シーケンス内の指定インデックス位置にある要素を返します。
public static TSource ElementAt<TSource>(
this IEnumerable<TSource> source,
int index);
ElementAt 演算子では、まず、元のシーケンスが IList<TSource> を実装するかどうかをチェックします。実装している場合は、元のシーケンスの IList<TSource> の実装を使用して、指定インデックス位置にある要素が取得されます。実装していない場合は、元のシーケンスが列挙され、インデックス位置の要素までスキップしてから、シーケンス内のその位置に見つかった要素が返されます。source 引数が NULL の場合は、ArgumentNullException がスローされます。インデックスがゼロ (0) 以下の場合、またはインデックスがシーケンス内の要素数以上の場合は、ArgumentOutOfRangeException がスローされます。
次の例では、3 番目に価格が高い製品が取得されます。
Product thirdMostExpensive =
products.OrderByDescending(p => p.UnitPrice).ElementAt(2);
ElementAtOrDefault
ElementAtOrDefault 演算子は、シーケンス内の指定インデックス位置にある要素を返しますが、インデックスが範囲外の場合は既定値を返します。
public static TSource ElementAtOrDefault<TSource>(
this IEnumerable<TSource> source,
int index);
ElementAtOrDefault 演算子では、まず、元のシーケンスが IList<TSource> を実装するかどうかをチェックします。実装している場合は、元のシーケンスの IList<TSource> の実装を使用して、指定インデックス位置にある要素が取得されます。実装していない場合は、元のシーケンスが列挙され、インデックス位置の要素までスキップしてから、シーケンス内のその位置に見つかった要素が返されます。source 引数が NULL の場合は、ArgumentNullException がスローされます。インデックスがゼロ (0) 以下の場合、またはインデックスがシーケンス内の要素数以上の場合は、default(TSource) が返されます。参照型および NULL 値を許容する型の既定値は NULL です。
DefaultIfEmpty
DefaultIfEmpty 演算子は、空のシーケンスに既定の要素を提供します。
public static IEnumerable<TSource> DefaultIfEmpty<TSource>(
this IEnumerable<TSource> source);
public static IEnumerable<TSource> DefaultIfEmpty<TSource>(
this IEnumerable<TSource> source,
TSource defaultValue);
DefaultIfEmpty 演算子は、演算子に渡された複数の引数に対応する、列挙可能なオブジェクトを割り当てて返します。source 引数が NULL の場合は、ArgumentNullException がスローされます。
DefaultIfEmpty から返されるオブジェクトを列挙すると、元のシーケンスが列挙され、その要素が返されます。元のシーケンスが空の場合は、指定された既定値を持つ単一要素が返されます。既定値の引数を指定していない場合は、空のシーケンスの代わりに default(TSource) が返されます。参照型および NULL 値を許容する型の既定値は NULL です。
DefaultIfEmpty 演算子とグループ化結合を組み合わせて、左外部結合を作成できます。例については、本資料の「GroupJoin」を参照してください。
生成演算子
Range
Range 演算子は、整数のシーケンスを生成します。
public static IEnumerable<int> Range(
int start,
int count);
Range 演算子は、引数に対応する、列挙可能なオブジェクトを割り当てて返します。count が負の値の場合、または start + count - 1 が int.MaxValue を超える場合は、ArgumentOutOfRangeException がスローされます。Range から返されるオブジェクトを列挙すると、start で指定される値から始まる連続する整数が count で指定された個数返されます。
次の例では、0 から 99 までの数値の 2 乗から成る配列が作成されます。
int[] squares = Sequence.Range(0, 100).Select(x => x * x).ToArray();
Repeat
Repeat 演算子は、値を指定された回数分繰り返すシーケンスを生成します。
public static IEnumerable<TResult> Repeat<TResult>(
TResult element,
int count);
Repeat 演算子は、引数に対応する、列挙可能なオブジェクトを割り当てて返します。回数に負の値が指定された場合は、ArgumentOutOfRangeException がスローされます。Repeat から返されるオブジェクトを列挙すると、element が count 個返されます。
次の例では、値 -1 の要素を 256 個含む long[] が作成されます。
long[] x = Sequence.Repeat(-1L, 256).ToArray();
Empty
Empty 演算子は、指定された型の空のシーケンスを返します。
public static IEnumerable<TResult> Empty<TResult>();
Empty 演算子は、指定された型の 1 つの空のシーケンスをキャッシュします。Empty から返されるオブジェクトを列挙しても、何も返されません。
次の例では、顧客の空のシーケンスが取得されます。
IEnumerable<Customer> noCustomers = Sequence.Empty<Customer>();
限定子
Any
Any 演算子は、シーケンスのいずれかの要素が条件を満たすかどうかをチェックします。
public static bool Any<TSource>(
this IEnumerable<TSource> source);
public static bool Any<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate);
Any 演算子は元のシーケンスを列挙し、いずれかの要素が述語で指定されたテストを満たす場合に TRUE を返します。述語関数を指定していない場合、元のシーケンスに要素が含まれていれば、Any 演算子は単純に TRUE を返します。
元のシーケンスの列挙は、結果が判明した時点で即時終了します。
いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
次の例では、価格が 100 以上の製品のうち、在庫切れになった製品があるかどうかをチェックします。
bool b = products.Any(p => p.UnitPrice >= 100 && p.UnitsInStock == 0);
All
All 演算子は、シーケンスのすべての要素が条件を満たすかどうかをチェックします。
public static bool All<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate);
All 演算子は元のシーケンスを列挙し、すべての要素が述語で指定されたテストを満たす場合に TRUE を返します。
元のシーケンスの列挙は、結果が判明した時点で即時終了します。
いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
All 演算子は、空のシーケンスに対しては TRUE を返します。この動作は、確立済みの述語ロジックおよび SQL のような他のクエリ言語と一貫性を持たせています。
次の例では、全製品の在庫がある製品カテゴリの名前が作成されます。
IEnumerable<string> fullyStockedCategories =
products.
GroupBy(p => p.Category).
Where(g => g.Group.All(p => p.UnitsInStock > 0)).
Select(g => g.Key);
Contains
Contains 演算子は、指定された要素がシーケンスに含まれているかどうかをチェックします。
public static bool Contains<TSource>(
this IEnumerable<TSource> source,
TSource value);
public static bool Contains<TSource>(
this IEnumerable<TSource> source,
TSource value,
IEqualityComparer<TSource> comparer);
Contains 演算子では、まず、元のシーケンスが ICollection<TSource> を実装するかどうかをチェックします。実装されている場合、シーケンスの ICollection<TSource> の実装内の Contains メソッドを呼び出し、結果を取得します。実装されていない場合、元のシーケンスを列挙し、指定された値を含む要素が存在するかどうかを調べます。この場合、対応する要素が見つかった時点で、元のシーケンスの列挙を終了します。comparer 引数に NULL 以外を指定した場合は、指定した比較子を使用して要素と指定値が比較されます。それ以外の場合は、既定の等値比較子 EqualityComparer<TSource>.Default が使用されます。
source 引数が NULL の場合は、ArgumentNullException がスローされます。
集計演算子
Count
Count 演算子は、シーケンス内の要素数を数えます。
public static int Count<TSource>(
this IEnumerable<TSource> source);
public static int Count<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate);
述語が指定されていない Count 演算子では、まず、元のシーケンスが ICollection<TSource> を実装するかどうかをチェックします。実装されている場合、シーケンスの ICollection<TSource> の実装を使用して、要素数を取得します。実装されていない場合は、元のシーケンスを列挙して要素数を数えます。
述語が指定された Count 演算子では、元のシーケンスを列挙し、述語関数が TRUE を返す要素の数を数えます。
どちらの Count 演算子も、いずれかの引数が NULL の場合は ArgumentNullException がスローされ、カウントが int.MaxValue を超える場合は OverflowException がスローされます。
次の例では、ロンドン在住の顧客数が返されます。
int count = customers.Count(c => c.City == "London");
LongCount
LongCount 演算子は、シーケンス内の要素数を数えます。
public static long LongCount<TSource>(
this IEnumerable<TSource> source);
public static long LongCount<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate);
LongCount 演算子は、元のシーケンスを列挙し、述語関数が TRUE を返す要素の数を数えます。述語関数を指定していない場合、LongCount 演算子は単純に全要素数を数えます。要素数は long 型の値で返されます。
どちらの LongCount 演算子も、いずれかの引数が NULL の場合は ArgumentNullException がスローされ、カウントが long.MaxValue を超える場合は OverflowException がスローされます。
Sum
Sum 演算子は、数値のシーケンスの合計を計算します。
public static Numeric Sum(
this IEnumerable<Numeric> source);
public static Numeric Sum<TSource>(
this IEnumerable<TSource> source,
Func<TSource, Numeric> selector);
"数値" 型とは、 int、int?、long、long?、float、float?、double、double?、decimal、または decimal? のいずれかです。
Sum 演算子は、元のシーケンスを列挙し、要素ごとに選択関数を呼び出して、結果の値の合計を計算します。選択関数を指定していない場合は、要素自体の合計が計算されます。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。"数値" 型が int、int?、long、long?、decimal、および decimal? の場合、合計計算の中間結果がその "数値" 型を使用して表現できる値を超えると OverflowException がスローされます。float、float?、double、および double? の場合、合計計算の中間結果が double を使用して表現できる値を超えると、正または負の無限大が返されます。
Sum 演算子は、空のシーケンスに対してはゼロ (0) を返します。また、結果には NULL 値が含まれません ("数値" 型が NULL 値を許容する型の場合に NULL 値が生じる可能性があります)。
次の例では、顧客名とその顧客が指定年度に行った注文の合計から成るシーケンスが作成されます。
int year = 2005;
var namesAndTotals =
customers.
Select(c => new {
c.Name,
TotalOrders =
c.Orders.
Where(o => o.OrderDate.Year == year).
Sum(o => o.Total)
});
Min
Min 演算子は、数値のシーケンスの最小値を検索します。
public static Numeric Min(
this IEnumerable<Numeric> source);
public static TSource Min<TSource>(
this IEnumerable<TSource> source);
public static Numeric Min<TSource>(
this IEnumerable<TSource> source,
Func<TSource, Numeric> selector);
public static TResult Min<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TResult> selector);
"数値" 型とは、 int、int?、long、long?、float、float?、double、double?、decimal、または decimal? のいずれかです。
Min 演算子は、元のシーケンスを列挙し、要素ごとに選択関数を呼び出して、結果の値の最小値を検索します。選択関数を指定していない場合は、要素自体の最小値が検索されます。IComparable<TSource> インターフェイスの実装を使用して値が比較されます。このインターフェイスが実装されていない場合は、値の比較にジェネリックではない IComparable インターフェイスが使用されます。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
元の型が NULL 値を許容しない値型で、元のシーケンスが空の場合は、InvalidOperationException がスローされます。元の型が参照型か NULL 値を許容する型で、元のシーケンスが空か NULL 値のみを含む場合、NULL が返されます。
"数値" 型の Min 実装では、汎用のジェネリック演算子を上回る最適化が行われます。
次の例では、製品カテゴリごとに、名前と最低製品価格から成るシーケンスが作成されます。
var minPriceByCategory =
products.
GroupBy(p => p.Category).
Select(g => new {
Category = g.Key,
MinPrice = g.Group.Min(p => p.UnitPrice)
});
Max
Max 演算子は、数値のシーケンスの最大値を検索します。
public static Numeric Max(
this IEnumerable<Numeric> source);
public static TSource Max<TSource>(
this IEnumerable<TSource> source);
public static Numeric Max<TSource>(
this IEnumerable<TSource> source,
Func<TSource, Numeric> selector);
public static TResult Max<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TResult> selector);
"数値" 型とは、int、int?、long、long?、float、float?、double、double?、decimal、または decimal? のいずれかです。
Max 演算子は、元のシーケンスを列挙し、要素ごとに選択関数を呼び出して、結果の値の最大値を検索します。選択関数を指定していない場合は、要素自体の最大値が検索されます。IComparable<TSource> インターフェイスの実装を使用して値が比較されます。このインターフェイスが実装されていない場合は、値の比較にジェネリックではない IComparable インターフェイスが使用されます。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
元の型が NULL 値を許容しない値型で、元のシーケンスが空の場合は、InvalidOperationException がスローされます。元の型が参照型か NULL 値を許容する型で、元のシーケンスが空か NULL 値のみを含む場合、NULL が返されます。
"数値" 型の Max 実装では、汎用のジェネリック演算子を上回る最適化が行われます。
次の例では、2005 年に行われた最大の注文の合計を検索します。
decimal largestOrder =
customers.
SelectMany(c => c.Orders).
Where(o => o.OrderDate.Year == 2005).
Max(o => o.Total);
Average
Average 演算子は、数値のシーケンスの平均値を計算します。
public static Result Average(
this IEnumerable<Numeric> source);
public static Result Average<TSource>(
this IEnumerable<TSource> source,
Func<TSource, Numeric> selector);
"数値" 型とは、int、int?、long、long?、float、float?、double、double?、decimal、または decimal? のいずれかです。"数値" 型が int または long の場合は、"結果" 型は double になります。"数値" 型が int? または long? の場合は、"結果" 型は double? になります。それ以外の場合は、"数値" 型と "結果" 型は同じになります。
Average 演算子は、元のシーケンスを列挙し、要素ごとに選択関数を呼び出して、結果の値の平均値を計算します。選択関数を指定していない場合は、要素自体の平均値が計算されます。いずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
"数値" 型が int、int?、long、または long? の場合、要素の合計計算の中間結果が long で表現できる値を超えると、OverflowException がスローされます。"数値" 型が decimal または decimal? の場合、要素の合計計算の中間結果が decimal で表現できる値を超えると、OverflowException がスローされます。
int?、long?、float?、double?、または decimal? では、元のシーケンスが空か、NULL 値のみを含む場合、Average 演算子は NULL を返します。その他の場合に元のシーケンスが空であれば、Average 演算子は InvalidOperationException をスローします。
次の例では、顧客ごとに注文合計の平均値が計算されます。
var averageOrderTotals =
customers.
Select(c => new {
c.Name,
AverageOrderTotal = c.Orders.Average(o => o.Total)
});
Aggregate
Aggregate 演算子は、シーケンスに関数を適用します。
public static TSource Aggregate<TSource>(
this IEnumerable<TSource> source,
Func<TSource, TSource, TSource> func);
public static TAccumulate Aggregate<TSource, TAccumulate>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func);
public static TResult Aggregate<TSource, TAccumulate, TResult>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func,
Func<TAccumulate, TResult> resultSelector);
シード値を指定した Aggregate 演算子では、まず、シード値を内部累積値に代入します。次に元のシーケンスを列挙し、指定された関数を繰り返し呼び出して、次の累積値を計算します。指定された関数を呼び出すときは、最初の引数に現在の累積値を、2 番目の引数に現在のシーケンス要素を渡します。結果を選択する関数が指定されていない場合、演算子は最終累積値を結果として返します。結果を選択する関数が指定されている場合は、最終累積値を結果選択関数に渡し、その関数の結果値を返します。source、func、resultSelector のいずれかの引数が NULL の場合は、ArgumentNullException がスローされます。
Aggregate 演算子にシード値を指定しない場合は、元のシーケンスの先頭要素がシード値として使用されます。ただし、それ以外の機能は上記の説明どおりです。元のシーケンスが空の場合、シード値を指定しない Aggregate 演算子は InvalidOperationException をスローします。
次の例では、製品カテゴリごとに、カテゴリ名と最長製品名から成るシーケンスが作成されます。
var longestNamesByCategory =
products.
GroupBy(p => p.Category).
Select(g => new {
Category = g.Key,
LongestName =
g.Group.
Select(p => p.Name).
Aggregate((s, t) => t.Length > s.Length ? t : s)
});