C#でリストの最初のN要素を取得する方法?


384

Linqを使用してプロジェクトのバススケジュールをクエリし、いつでも次の5つのバス到着時刻を取得できるようにしたいと考えています。クエリを最初の5つの結果に制限するにはどうすればよいですか?

より一般的には、C#でリストの一部を取得するにはどうすればよいですか?(Pythonではmylist[:5]、最初の5つの要素を取得するために使用します。)

回答:


708
var firstFiveItems = myList.Take(5);

またはスライスする:

var secondFiveItems = myList.Skip(5).Take(5);

そしてもちろん、多くの場合、最初の5つのアイテムを何らかの順序に従って取得すると便利です。

var firstFiveArrivals = myList.OrderBy(i => i.ArrivalTime).Take(5);

87
たとえば、リストに3つの項目しかない場合、例外がスローされますか?それとも最大5つまで必要ですか?
bobek

87
@bobek:例外をスローしません。要素が足りない場合は、単にそれが持っているものを返します。
Joshua Pech、

1
正確に言うと、SkipとTakeを組み合わせて例外がスローされなかったため、一般的なコレクションを取得し、バッチごとにx項目を処理したかったので問題が解決しました
JohanLarsson

.Take(n)TakeIterator を返すことに注意してください。n要素が含まれているリストは返されません(その数が利用可能であると想定)。具体的な配列またはリストを取得するには、の結果で.ToArray()or .ToList()を使用しTakeます。
Andrew Webb

69

誰かが興味を持っている場合(質問でこのバージョンが要求されない場合でも)、C#2では次のようになります(私はいくつかの提案に従って、回答を編集しました)

myList.Sort(CLASS_FOR_COMPARER);
List<string> fiveElements = myList.GetRange(0, 5);

おそらく匿名の述語も追加しますか?
AlexeyMK 2008年

2
List <T> .Sortはvoidを返します。ソートしてから、GetRangeを個別に使用する必要があります。また、Comparison <T>匿名メソッドを使用して、CLASS_FOR_COMPARERを不要にすることもできます。
マークグラベル

@AlexeyMK-述語(Predicate <T>)ではなく、Comparison <T>を意味します-述語はデータのフィルタリングに使用されます
Marc Gravell

この答えは今でも、10年後や多くのC#バージョンでも役立つと思います。リストがある特定のケースについて。特に多くのアイテムをスキップしている場合。たとえば、100万個のアイテムのリストがあり、そのうちの5個のスライスをリストの中に入れたいとします。GetRangeは、それらを取得するためにどこへ行くかを正確に知っています。Skip+ Takeが同じくらい賢いのか、それともスキップされたアイテムを列挙するのかわかりません。そして、私は知る必要はありません-GetListを使用するだけです(リストが与えられた場合)。2番目のパラメーターが(最後のインデックスではなく)countであることを確認してください。
ToolmakerSteve 2018年

良い点.Take(n)は、nそれが機能するシーケンスの要素よりも少ない場合でも心配する必要がないことです。問題List<T>.GetRange(0, count)はあなたが心配しArgumentExceptionなければならないことです... countアイテムがない場合はあなたが得るでしょう。
Andrew Webb

5

同様にpaginationあなたが取るためのフォーミュラの下に使用することができますslice of list or elements

var slice = myList.Skip((pageNumber - 1) * pageSize)
                  .Take(pageSize);

例1:最初の5つのアイテム

var pageNumber = 1;
var pageSize = 5;

例2:2番目の5つのアイテム

var pageNumber = 2;
var pageSize = 5;

例3:3番目の5つのアイテム

var pageNumber = 3;
var pageSize = 5;

予告フォーミュラパラメータにする場合pageSize = 5pageNumber、あなたが変更スライス内の項目数を変更したい場合は、変更されますpageSize


1

最初の5つの要素を取得するには、次のような式を使用します。

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5);

または

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5).OrderBy([ORDER EXPR]);

LINQエンジンは実行の遅延のためにすべてのリストをスキャンせず、すべての配列をソートしないため、orderByバリアントよりも高速になります。

class MyList : IEnumerable<int>
{

    int maxCount = 0;

    public int RequestCount
    {
        get;
        private set;
    }
    public MyList(int maxCount)
    {
        this.maxCount = maxCount;
    }
    public void Reset()
    {
        RequestCount = 0;
    }
    #region IEnumerable<int> Members

    public IEnumerator<int> GetEnumerator()
    {
        int i = 0;
        while (i < maxCount)
        {
            RequestCount++;
            yield return i++;
        }
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    #endregion
}
class Program
{
    static void Main(string[] args)
    {
        var list = new MyList(15);
        list.Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 5;

        list.Reset();
        list.OrderBy(q => q).Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 15;

        list.Reset();
        list.Where(q => (q & 1) == 0).Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 9; (first 5 odd)

        list.Reset();
        list.Where(q => (q & 1) == 0).Take(5).OrderBy(q => q).ToArray();
        Console.WriteLine(list.RequestCount); // 9; (first 5 odd)
    }
}

25
選択した後、最初の5つの要素のみを注文することを除きます。それはより高速かもしれませんが、人々が実際に達成したいものである可能性が低い異なるセマンティクスも持っています。
グレッグビーチ、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.