LINQ

2008-08-01 15 views
64

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

उत्तर

34

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

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

आप MSDN कोड गैलरी पृष्ठ से कोड प्राप्त कर सकते हैं: Pipelines, Filters, Fluent API and LINQ to SQL

59

Skip और Take एक्सटेंशन विधियों के साथ यह बहुत आसान है।

var query = from i in ideas 
      select i; 

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

मुझे विश्वास है कि यह कुछ इस तरह करने के लिए ठीक है। उसके पास जवाब हो सकता है लेकिन शायद वह देखना चाहता है कि अन्य लोग भी साथ आ सकते हैं। –

+11

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

6

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

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 खुद पेजिंग को लागू करने की कर रहे हैं।

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); 
} 

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

10

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

// 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>)। आप एक अतिरिक्त संग्रह के रूप में प्रत्येक पृष्ठ को संभालने के लिए है, लेकिन जैसे

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

बेशक: यह आप इसे कैसे Skip और Take का उपयोग कर एक साथ कर सकते हैं pageRange ऊपर बनाया से सूचकांक चयन करने के साथ है यदि आप दोहराना शुरू कर रहे हैं तो यह वास्तव में संभालना आसान है।


एक लाइनर 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 
    } 
}