Bagaimana cara mendapatkan elemen N pertama dari daftar di C #?


384

Saya ingin menggunakan Linq untuk menanyakan jadwal bus di proyek saya, sehingga kapan saja saya bisa mendapatkan 5 kali kedatangan bus berikutnya. Bagaimana saya bisa membatasi permintaan saya ke 5 hasil pertama?

Secara umum, bagaimana saya bisa mengambil sepotong daftar di C #? (Dengan Python saya akan gunakan mylist[:5]untuk mendapatkan 5 elemen pertama.)

Jawaban:


709
var firstFiveItems = myList.Take(5);

Atau untuk mengiris:

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

Dan tentu saja seringkali lebih mudah untuk mendapatkan lima item pertama sesuai dengan beberapa jenis pesanan:

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

87
Apakah ada pengecualian jika hanya ada, misalnya, 3 item dalam daftar? Atau akankah dibutuhkan sebanyak 5?
bobek

87
@bobek: Tidak ada pengecualian. Ini hanya mengembalikan apa yang dimilikinya jika tidak ada cukup elemen.
Joshua Pech

1
tepatnya, tidak ada pengecualian yang dilemparkan Lewati dan Ambil gabungan memecahkan masalah saya karena saya ingin mengambil koleksi generik dan memproses x item per batch
JohanLarsson

Perlu dicatat bahwa .Take(n)mengembalikan TakeIterator; itu tidak mengembalikan daftar dengan nelemen di dalamnya (dengan asumsi bahwa banyak yang tersedia). Gunakan .ToArray()atau .ToList()pada hasil Takeuntuk mendapatkan array atau daftar konkret.
Andrew Webb

69

Jika ada yang tertarik (walaupun pertanyaannya tidak menanyakan versi ini), dalam C # 2 adalah: (Saya telah mengedit jawabannya, mengikuti beberapa saran)

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

Mungkin menambahkan predikat anonim juga?
AlexeyMK

2
Daftar <T> .Sort mengembalikan batal; Anda perlu menyortir, lalu gunakan GetRange secara terpisah. Anda juga bisa menggunakan metode anonim Perbandingan <T> untuk menghapus kebutuhan CLASS_FOR_COMPARER.
Marc Gravell

@AlexeyMK - maksud Anda adalah Perbandingan <T>, bukan predikat (Predikat <T>) - predikat digunakan untuk memfilter data
Marc Gravell

Saya percaya jawaban ini berguna bahkan sekarang, 10 tahun dan banyak versi C # kemudian. Untuk kasus khusus di mana Anda memiliki daftar. Apalagi jika Anda melewatkan banyak item. Misalnya Anda memiliki daftar satu juta item, dan Anda ingin sepotong 5 dari mereka, jauh ke dalam daftar. GetRange tahu persis ke mana harus pergi untuk mengambilnya. Saya tidak tahu apakah Skip+ Takesama pintarnya, atau apakah ia menyebutkan item yang dilompati. Dan saya tidak perlu tahu - Saya hanya menggunakan GetRange (ketika diberi Daftar). Pastikan Anda menyadari bahwa parameter kedua adalah jumlah (bukan indeks terakhir ).
ToolmakerSteve

Yang menyenangkan tentang itu .Take(n)adalah Anda tidak perlu khawatir jika ada kurang dari nelemen dalam urutannya. Masalahnya List<T>.GetRange(0, count)adalah Anda harus khawatir .... Anda akan mendapatkan ArgumentExceptionjika tidak ada countbarang.
Andrew Webb

5

Seperti paginationAnda dapat menggunakan formule di bawah ini untuk mengambil slice of list or elements:

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

Contoh 1: lima item pertama

var pageNumber = 1;
var pageSize = 5;

Contoh 2: lima item kedua

var pageNumber = 2;
var pageSize = 5;

Contoh 3: lima item ketiga

var pageNumber = 3;
var pageSize = 5;

Jika memperhatikan parameter formule pageSize = 5dan pageNumberberubah, jika Anda ingin mengubah jumlah item dalam mengiris Anda berubah pageSize.


1

Untuk mengambil 5 elemen pertama lebih baik gunakan ekspresi seperti ini:

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

atau

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

Ini akan lebih cepat daripada varian OrderBy, karena mesin LINQ tidak akan memindai melalui semua daftar karena eksekusi tertunda, dan tidak akan mengurutkan semua array.

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
Kecuali bahwa Anda sekarang memesan hanya 5 elemen pertama setelah Anda memilihnya. Mungkin lebih cepat, tetapi juga memiliki semantik yang berbeda, yang cenderung menjadi apa yang orang ingin capai.
Greg Beech
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.