1. ホーム
  2. c#

[解決済み】Linqを使用してコレクションの最後のN個の要素を取得するには?

2022-03-28 10:47:25

質問

あるコレクションが与えられたとき、そのコレクションの最後のN個の要素を取得する方法はありますか? フレームワークにメソッドがない場合、これを行うための拡張メソッドを書くには何がベストでしょうか?

どのように解決するのですか?

collection.Skip(Math.Max(0, collection.Count() - N));

この方法は、ソートに依存することなく項目の順序を維持し、いくつかのLINQプロバイダで幅広い互換性を持っています。

を呼び出さないように注意することが重要です。 Skip を負の数で指定します。Entity Framework などのプロバイダでは、負の数の引数を指定すると ArgumentException が発生します。への呼び出しは Math.Max は、これをうまく回避しています。

以下のクラスは、拡張メソッドに必要なもの、すなわち、静的クラス、静的メソッド、および this というキーワードがあります。

public static class MiscExtensions
{
    // Ex: collection.TakeLast(5);
    public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int N)
    {
        return source.Skip(Math.Max(0, source.Count() - N));
    }
}

パフォーマンスについて簡単にご説明します。

を呼び出すので Count() は特定のデータ構造の列挙を引き起こす可能性があり、このアプローチにはデータに対する2つのパスが発生するリスクがあります。実際、リストや配列、そして EF クエリでさえも最適化されたものが存在し、その中で Count() の演算をO(1)の時間で実行できる。

しかし、どうしても前方のみの列挙体を使い、2回のパスを避けたい場合は、次のようなワンパス・アルゴリズムを考えてみてください。 ラッセ・V・カールセン または マーク・バイヤー を記述します。これらのアプローチでは、列挙中に一時的なバッファを使用してアイテムを保持し、コレクションの終端が見つかったらそれを返します。