วิธีรับองค์ประกอบ N แรกของรายการใน C #


384

ฉันต้องการใช้ Linq เพื่อสอบถามตารางเวลารถบัสในโครงการของฉันเพื่อที่ว่าเมื่อใดก็ตามที่ฉันสามารถรับรถบัสมาถึง 5 ครั้งต่อไป ฉันจะ จำกัด ข้อความค้นหาของฉันไว้ที่ผลลัพธ์ 5 รายการแรกได้อย่างไร

โดยทั่วไปฉันจะนำชิ้นส่วนของรายการใน C # ได้อย่างไร (ใน Python ฉันจะใช้mylist[:5]เพื่อรับ 5 องค์ประกอบแรก)

คำตอบ:


706
var firstFiveItems = myList.Take(5);

หรือชิ้น:

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

และแน่นอนบ่อยครั้งที่สะดวกในการรับห้ารายการแรกตามคำสั่งบางประเภท:

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

87
มันมีข้อยกเว้นถ้ามีเพียง 3 รายการในรายการหรือไม่? หรือจะใช้มากถึง 5
bobek

87
@bobek: มันไม่ได้ทำให้เกิดข้อยกเว้น มันจะคืนสิ่งที่มีหากไม่มีองค์ประกอบเพียงพอ
Joshua Pech

1
ว่าไม่มีข้อยกเว้นโยนข้ามและใช้เวลารวมกันแก้ปัญหาของฉันเป็นที่ฉันต้องการใช้คอลเลกชันใด ๆ ทั่วไปและกระบวนการ x รายการต่อชุด
JohanLarsson

ควรสังเกตว่า.Take(n)ส่งคืน TakeIterator มันจะไม่ส่งคืนรายการที่มีnองค์ประกอบอยู่ในนั้น (สมมติว่ามีหลายรายการ) ใช้.ToArray()หรือ.ToList()จากผลลัพธ์ของการTakeรับอาร์เรย์หรือรายการที่เป็นรูปธรรม
Andrew Webb

69

ในกรณีที่ทุกคนสนใจ (แม้ว่าคำถามจะไม่ขอรุ่นนี้) ใน C # 2 จะเป็น: (ฉันได้แก้ไขคำตอบแล้วทำตามคำแนะนำ)

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

อาจเพิ่มภาคแสดงที่ไม่ระบุชื่อด้วยหรือไม่
AlexeyMK

2
List <T> .Sort จะคืนค่าเป็นโมฆะ คุณต้องเรียงลำดับจากนั้นใช้ GetRange แยกกัน นอกจากนี้คุณยังสามารถใช้วิธีเปรียบเทียบโดยไม่ระบุชื่อเพื่อลบความต้องการ CLASS_FOR_COMPARER
Marc Gravell

@AlexeyMK - คุณหมายถึงการเปรียบเทียบ <T> ไม่ใช่เพรดิเคต (เพรดิเคต <T>) - เพรดิเคตจะใช้ในการกรองข้อมูล
Marc Gravell

ฉันเชื่อว่าคำตอบนี้มีประโยชน์แม้ตอนนี้ 10 ปีและรุ่น C # หลายรุ่นในภายหลัง สำหรับกรณีเฉพาะที่คุณมีรายการ โดยเฉพาะอย่างยิ่งถ้าคุณกำลังข้ามหลายรายการ เช่นคุณมีรายชื่อหนึ่งล้านรายการและคุณต้องการชิ้นส่วน 5 รายการจากรายการ GetRange รู้ว่าจะไปคว้าพวกเขาได้ที่ไหน ฉันไม่ทราบว่าSkip+ Takeเป็นสมาร์ทหรือระบุว่าเป็นรายการที่ข้าม และฉันไม่จำเป็นต้องรู้ - ฉันแค่ใช้ GetRange (เมื่อได้รับรายชื่อ) เพียงให้แน่ใจว่าคุณรู้ว่าพารามิเตอร์ที่สองนั้นถูกนับ (แทนที่จะเป็นดัชนีล่าสุด )
ToolmakerSteve

สิ่งที่ดีเกี่ยวกับการ.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: ห้ารายการแรก

var pageNumber = 1;
var pageSize = 5;

ตัวอย่างที่ 2: ห้ารายการที่สอง

var pageNumber = 2;
var pageSize = 5;

ตัวอย่างที่ 3: สามรายการที่ห้า

var pageNumber = 3;
var pageSize = 5;

หากแจ้งให้ทราบล่วงหน้าพารามิเตอร์ Formule pageSize = 5และมีการเปลี่ยนแปลงถ้าคุณต้องการที่จะเปลี่ยนหมายเลขของรายการในหั่นคุณเปลี่ยนpageNumberpageSize


1

ในการใช้ 5 องค์ประกอบแรกให้ใช้นิพจน์อย่างนี้ดีกว่า:

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

หรือ

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

มันจะเร็วกว่าชุดคำสั่งโดยตัวแปรเพราะเอ็นจิน LINQ จะไม่สแกนรายการทั้งหมดเนื่องจากการดำเนินการล่าช้าและจะไม่เรียงลำดับอาร์เรย์ทั้งหมด

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 องค์ประกอบแรกหลังจากที่คุณเลือก อาจเร็วกว่านี้ แต่ก็มีความหมายต่างกันซึ่งมีโอกาสน้อยกว่าที่คนทั่วไปต้องการบรรลุ
Greg Beech
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.