LINQ के साथ एक संग्रह पेजिंग


84

आप LINQ में दिए गए संग्रह के माध्यम से कैसे पृष्ठ देखते हैं कि आपके पास a startIndexऔर a है count?

जवाबों:


43

कुछ महीने पहले मैंने धाराप्रवाह इंटरफेस और LINQ के बारे में एक ब्लॉग पोस्ट लिखा था जिसमें IQueryable<T>एक LINQ संग्रह को पृष्ठांकित करने का निम्नलिखित प्राकृतिक तरीका प्रदान करने के लिए एक एक्सटेंशन विधि और दूसरी कक्षा का उपयोग किया गया था।

var query = from i in ideas
            select i;
var pagedCollection = query.InPagesOf(10);
var pageOfIdeas = pagedCollection.Page(2);

आप MSDN कोड गैलरी पेज से कोड प्राप्त कर सकते हैं: पाइपलाइन, फिल्टर, धाराप्रवाह एपीआई और LINQ से SQL


64

यह Skipऔर Takeविस्तार विधियों के साथ बहुत सरल है ।

var query = from i in ideas
            select i;

var paggedCollection = query.Skip(startIndex).Take(count);

3
मेरा मानना ​​है कि ऐसा कुछ करना ठीक है। उसके पास एक उत्तर हो सकता है लेकिन शायद वह यह देखना चाहता है कि अन्य लोग भी क्या कर सकते हैं।
आउटलाव प्रोग्रामर

11
यह मूल रूप से StackOverflow की बीटा अवधि के पहले दिन के दौरान पोस्ट किया गया था, इस प्रकार लेख आईडी के लिए 66। मैं सिस्टम का परीक्षण कर रहा था, जेफ के लिए। इसके अलावा यह सामान्य परीक्षण बकवास के बजाय उपयोगी जानकारी की तरह लगता था जो कभी-कभी बीटा परीक्षण से निकलता है।
निक बर्र्डी

14

मैंने इसे थोड़ा अलग तरीके से हल किया है कि दूसरों के पास क्या है जैसा कि मुझे एक पुनरावर्तक के साथ अपना पैजेंटिनेटर बनाना था। इसलिए मैंने पहले उन वस्तुओं के संग्रह के लिए पृष्ठ संख्याओं का एक संग्रह बनाया जो मेरे पास हैं:

// assumes that the item collection is "myItems"

int pageCount = (myItems.Count + PageSize - 1) / PageSize;

IEnumerable<int> pageRange = Enumerable.Range(1, pageCount);
   // pageRange contains [1, 2, ... , pageCount]

इसके उपयोग से मैं आइटम संग्रह को "पृष्ठों" के संग्रह में आसानी से विभाजित कर सकता था। इस मामले में एक पृष्ठ सिर्फ वस्तुओं का संग्रह है ( IEnumerable<Item>)। यह है कि आप इसका उपयोग कैसे कर सकते हैं Skipऔर Takeसाथ में pageRangeऊपर दिए गए सूचकांक से सूचकांक का चयन कर सकते हैं :

IEnumerable<IEnumerable<Item>> pageRange
    .Select((page, index) => 
        myItems
            .Skip(index*PageSize)
            .Take(PageSize));

बेशक आपको एक अतिरिक्त संग्रह के रूप में प्रत्येक पृष्ठ को संभालना है लेकिन उदाहरण के लिए यदि आप रिपीटर्स को नेस्ट कर रहे हैं तो यह वास्तव में संभालना आसान है।


एक लाइनर TLDR संस्करण इस होगा:

var pages = Enumerable
    .Range(0, pageCount)
    .Select((index) => myItems.Skip(index*PageSize).Take(PageSize));

जिसका उपयोग इस प्रकार किया जा सकता है:

for (Enumerable<Item> page : pages) 
{
    // handle page

    for (Item item : page) 
    {
        // handle item in page
    }
}

10

यह प्रश्न कुछ पुराना है, लेकिन मैं अपने पेजिंग एल्गोरिथ्म को पोस्ट करना चाहता था जो पूरी प्रक्रिया (उपयोगकर्ता इंटरैक्शन सहित) दिखाता है।

const int pageSize = 10;
const int count = 100;
const int startIndex = 20;

int took = 0;
bool getNextPage;
var page = ideas.Skip(startIndex);

do
{
    Console.WriteLine("Page {0}:", (took / pageSize) + 1);
    foreach (var idea in page.Take(pageSize))
    {
        Console.WriteLine(idea);
    }

    took += pageSize;
    if (took < count)
    {
        Console.WriteLine("Next page (y/n)?");
        char answer = Console.ReadLine().FirstOrDefault();
        getNextPage = default(char) != answer && 'y' == char.ToLowerInvariant(answer);

        if (getNextPage)
        {
            page = page.Skip(pageSize);
        }
    }
}
while (getNextPage && took < count);

हालाँकि, यदि आप प्रदर्शन के बाद हैं, और उत्पादन कोड में, हम सभी प्रदर्शन के बाद हैं, तो आपको LINQ के पेजिंग का उपयोग नहीं करना चाहिए जैसा कि ऊपर दिखाया गया है, बल्कि IEnumeratorअपने आप को पेजिंग लागू करने के लिए अंतर्निहित है। तथ्य की बात के रूप में, यह ऊपर दिखाए गए LINQ-एल्गोरिथ्म के रूप में सरल है, लेकिन अधिक प्रदर्शन करने वाला:

const int pageSize = 10;
const int count = 100;
const int startIndex = 20;

int took = 0;
bool getNextPage = true;
using (var page = ideas.Skip(startIndex).GetEnumerator())
{
    do 
    {
        Console.WriteLine("Page {0}:", (took / pageSize) + 1);

        int currentPageItemNo = 0;
        while (currentPageItemNo++ < pageSize && page.MoveNext())
        {
            var idea = page.Current;
            Console.WriteLine(idea);
        }

        took += pageSize;
        if (took < count)
        {
            Console.WriteLine("Next page (y/n)?");
            char answer = Console.ReadLine().FirstOrDefault();
            getNextPage = default(char) != answer && 'y' == char.ToLowerInvariant(answer);
        }
    }
    while (getNextPage && took < count);
}

स्पष्टीकरण: Skip()"कैस्केडिंग तरीके" में कई बार उपयोग करने का नकारात्मक पक्ष यह है कि यह वास्तव में पुनरावृत्ति के "पॉइंटर" को संग्रहीत नहीं करेगा, जहां यह पिछली बार छोड़ दिया गया था। - इसके बजाय मूल अनुक्रम को स्किप कॉल के साथ फ्रंट-लोड किया जाएगा, जो बार-बार "पहले से ही उपभोग किए गए" पृष्ठों को "उपभोग" करने का नेतृत्व करेगा। - आप खुद को साबित कर सकते हैं, जब आप अनुक्रम बनाते हैं ideasताकि यह दुष्प्रभाव पैदा करे। -> अगर आपने 10-20 और 20-30 को छोड़ दिया है और 40+ प्रोसेस करना चाहते हैं, तो आपको 40-30 से पहले पुनरावृत्त होने से पहले 10-30 के सभी साइड इफेक्ट्स दिखाई देंगे। वेरिएंट IEnumerableसीधे इंटरफ़ेस का उपयोग करने के बजाय, अंतिम तार्किक पृष्ठ के अंत की स्थिति को याद रखेगा, इसलिए कोई स्पष्ट लंघन की आवश्यकता नहीं है और दुष्प्रभाव दोहराए नहीं जाएंगे।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.