LINQ - 要素の取得
概要
LINQには、単一または複数の要素を取得するための様々なメソッドが存在する。
これらのメソッドは、コレクションから特定の条件に合う要素や位置に基づいた要素を効率的に取得するのに役立つ。
単一の要素を取得するメソッドとしては、First、FirstOrDefault、Single、SingleOrDefault、Last、LastOrDefault等のメソッドがある。
Firstメソッドは最初の要素、Lastメソッドは最後の要素を返す。
Singleメソッドは唯一の要素を返すが、複数の要素が存在する場合は例外をスローする。
これらのメソッドにおいて、サフィックスに"OrDefault"が付加されたメソッド (FirstOrDefaultメソッド等) は、要素が見つからない場合にデフォルト値を返す。
ElementAtメソッドは、指定されたインデックスの要素を取得する。
ElementAtOrDefaultメソッドは、インデックスが範囲外の場合にデフォルト値を返す。
複数の要素を取得するメソッドには、Where、Take、Skip、TakeWhile、SkipWhile等のメソッドがある。
Whereメソッドは条件に一致する全ての要素、Takeメソッドは指定した数の要素を先頭から取得する。
Skipメソッドは、指定した数の要素をスキップした後の残りの要素を返す。
TakeWhileメソッドおよびSkipWhileメソッドは、条件が真である間要素を取得またはスキップする。
これらのメソッドを組み合わせることにより、複雑なデータ取得操作を簡潔に表現することができる。
例えば、WhereメソッドとTakeメソッドを組み合わせて、条件に一致する最初のN個の要素を取得することができる。
LINQのこれらのメソッドは、クエリ構文または拡張メソッド構文を使用して呼び出すことができ、コードの可読性と保守性を向上させるのに役立つ。
結果の表示
ここでは、結果の表示において、独自の拡張メソッドToResult(this IEnumerable)を使用している。
// 結果表示用の拡張メソッド
public static String ToResult<TSource>(this IEnumerable<TSource> source)
{
return "{" + string.Join(", ", source) + "}";
}
public static String ToResult<TKey, TSource>(this IEnumerable<IGrouping<TKey, TSource>> source)
{
return source.Select(group => string.Format("Key={0}, Source={1}", group.Key, group.ToResult())).ToResult();
}
要素の取得(単一)
該当の要素がない場合
- ~OrDefaultが付いていないメソッドは例外をスローする。
- ~OrDefaultが付いたメソッドは型の規定値を返す。
メソッド名 | 機能 |
---|---|
ElementAt ElementAtOrDefault |
指定した位置(インデックス)にある要素を返す。 ElementAtメソッドは、指定したインデックスが範囲外の場合に例外をスローする。 ElementAtOrDefaultメソッドは、その場合にデフォルト値を返す。 これらは、配列のようにインデックスベースでアクセスしたい場合に便利である。 |
First FirstOrDefault |
シーケンスの最初の要素を返す。 条件を指定することも可能であり、その場合は条件を満たす最初の要素を返す。 Firstメソッドは、要素が見つからない場合に例外をスローする。 FirstOrDefaultメソッドは、デフォルト値を返す。 これらは、条件に合う要素が1つ以上あることが期待される場合や最初の要素のみが必要な場合に使用する。 |
Last LastOrDefault |
Firstメソッド / FirstOrDefaultメソッドの逆で、シーケンスの最後の要素を返す。 同様に条件指定も可能である。 Lastメソッドは、要素が見つからない場合に例外をスローする。 LastOrDefaultメソッドは、デフォルト値を返す。 これらは、最後の要素や条件を満たす最後の要素が必要な場合に使用する。 |
Single SingleOrDefault |
シーケンス内の唯一の要素を返す。 条件指定も可能である。 Singleメソッドは、要素が1つでない場合 (0個または2個以上) に例外をスローする。 SingleOrDefaultメソッドは、要素が見つからない場合にデフォルト値を返すが、2つ以上ある場合は例外をスローする。 これらは、シーケンスに厳密に1つの要素しかないことを保証したい場合に使用する。 |
var source = new[] { 3, 4, 5, 6, 7, 8, 9, 9 };
Console.WriteLine(source.ElementAt(2));
// -> 5
Console.WriteLine(source.ElementAtOrDefault(10));
// -> 0
Console.WriteLine(source.First());
// -> 3
Console.WriteLine(source.First(e => e > 5));
// -> 6
var emptyList = new List<int>();
Console.WriteLine($"FirstOrDefault() on empty list: {emptyList.FirstOrDefault()}");
// -> int型のデフォルト値 : 0
Console.WriteLine(source.Last());
// -> 9
Console.WriteLine(source.Last(e => e < 5));
// -> 4
Console.WriteLine(source.LastOrDefault(x => x > 10));
// -> int型のデフォルト値 : 0
Console.WriteLine(source.Single());
// -> System.InvalidOperationException: シーケンスに複数の要素が含まれている
Console.WriteLine(source.Single(e => e < 4 ));
// -> 3
Console.WriteLine(source.SingleOrDefault(x => x == 3));
// -> 3
要素の取得(複数)
した表のメソッドは、単独で使用することもできるが、組み合わせることでより複雑なデータ操作を実現できる。
例えば、WhereメソッドでフィルタリングしてからTakeメソッドで上位N個を取得する場合、あるいは、SkipメソッドとTakeメソッドを組み合わせてページネーションを実装することが可能である。
メソッド名 | 機能 |
---|---|
Where | 条件を満たす要素をすべて返す。 |
Distinct | 重複を除いたシーケンスを返す。 |
Skip | 先頭から指定された数の要素をスキップして、残りのシーケンスを返す。 これは、ページネーションや、データの一部を除外する場合に便利である。 例えば、最初の10個の要素を無視して残りを取得するような場合に使用する。 |
SkipWhile | 先頭から指定された条件を満たさなくなるまで要素をスキップして、残りのシーケンスを返す。 これは、特定の条件が満たされるまでデータをスキップしたい場合に使用する。 例えば、ある値を超えるまでの要素をスキップする場合等に有効である。 |
Take | 先頭から指定された数の要素を返す。 これは、結果セットのサイズを制限する場合、または、最初のN個の要素のみが必要な場合に使用する。 |
TakeWhile | 先頭から指定された条件を満たす要素を返す。 条件が偽になった時点で取得を停止する。 これは、特定の条件を満たす要素のみを連続して取得したい場合に使用する。 |
var source = new[] { 3, 4, 5, 6, 7, 8, 9, 9 };
Console.WriteLine(source.Where(e => e > 5).ToResult());
// → {6, 7, 8, 9, 9}
Console.WriteLine(source.Distinct().ToResult());
// → {3, 4, 5, 6, 7, 8, 9}
Console.WriteLine(source.Skip(5).ToResult());
// → {8, 9, 9}
Console.WriteLine(source.SkipWhile(e => e < 5).ToResult());
// → {5, 6, 7, 8, 9, 9}
Console.WriteLine(source.Take(5).ToResult());
// → {3, 4, 5, 6, 7}
Console.WriteLine(source.TakeWhile(e => e < 5).ToResult());
// → {3, 4}
// 組み合わせ 1
Console.WriteLine(numbers.Where(x => x % 2 == 0).Take(2).ToResult());
// -> {4, 6}
// 組み合わせ 2
Console.WriteLine(source.Skip(2).Take(4).ToResult());
// -> {5, 6, 7, 8}
// 組み合わせ 3
Console.WriteLine(source.Where(x => x > 4).Distinct().ToResult());
// -> {5, 6, 7, 8, 9}