2010-02-27 23 views
9

मैं एक पायथन इटरेटर के माध्यम से "पृष्ठ" के लिए एक रास्ता तलाश रहा हूं। यही है, मैं एक दिए गए इटरेटर iter और पेज_साइज को एक अन्य इटरेटर के साथ लपेटना चाहूंगा जो इसे "पृष्ठों" की श्रृंखला के रूप में आइटम से वापस कर देगा। प्रत्येक पृष्ठ स्वयं पृष्ठ_साइज पुनरावृत्तियों के साथ एक पुनरावर्तक होगा।पायथन इटरेटर्स के लिए पेजर कैसे लिखें?

मैंने itertools के माध्यम से देखा और मैंने देखा सबसे नज़दीकी चीज़ itertools.islice है। कुछ मायनों में, मुझे जो चाहिए वह itertools.chain के विपरीत है - एक इटरेटर में एक साथ इटरेटर की श्रृंखला को चेन करने की बजाय, मैं एक छोटे से इटरेटर की श्रृंखला में एक इटरेटर को तोड़ना चाहता हूं। मैं itertools में एक पेजिंग समारोह खोजने की उम्मीद कर रहा था लेकिन एक का पता नहीं लगा सका।

मैं निम्नलिखित पेजर वर्ग और प्रदर्शन के साथ आया था।

class pager(object): 
    """ 
    takes the iterable iter and page_size to create an iterator that "pages through" iter. That is, pager returns a series of page iterators, 
    each returning up to page_size items from iter. 
    """ 
    def __init__(self,iter, page_size): 
     self.iter = iter 
     self.page_size = page_size 
    def __iter__(self): 
     return self 
    def next(self): 
     # if self.iter has not been exhausted, return the next slice 
     # I'm using a technique from 
     # https://stackoverflow.com/questions/1264319/need-to-add-an-element-at-the-start-of-an-iterator-in-python 
     # to check for iterator completion by cloning self.iter into 3 copies: 
     # 1) self.iter gets advanced to the next page 
     # 2) peek is used to check on whether self.iter is done 
     # 3) iter_for_return is to create an independent page of the iterator to be used by caller of pager 
     self.iter, peek, iter_for_return = itertools.tee(self.iter, 3) 
     try: 
      next_v = next(peek) 
     except StopIteration: # catch the exception and then raise it 
      raise StopIteration 
     else: 
      # consume the page from the iterator so that the next page is up in the next iteration 
      # is there a better way to do this? 
      # 
      for i in itertools.islice(self.iter,self.page_size): pass 
      return itertools.islice(iter_for_return,self.page_size) 



iterator_size = 10 
page_size = 3 

my_pager = pager(xrange(iterator_size),page_size) 

# skip a page, then print out rest, and then show the first page 
page1 = my_pager.next() 

for page in my_pager: 
    for i in page: 
     print i 
    print "----" 

print "skipped first page: " , list(page1) 

मैं कुछ प्रतिक्रिया के लिए देख रहा हूँ और निम्न प्रश्नों है

  1. वहाँ एक पेजर पहले से ही है itertools कि एक पेजर कि मैं अनदेखी कर रहा हूँ में कार्य करता है में?
  2. क्लोनिंग self.iter 3 बार मुझे लगता है। एक क्लोन यह जांचना है कि क्या self.iter में कोई और आइटम है या नहीं। मैंने a technique Alex Martelli suggested के साथ जाने का फैसला किया (पता है कि उन्होंने wrapping technique लिखा था)। दूसरा क्लोन लौटा हुआ पृष्ठ आंतरिक इटरेटर (self.iter) से स्वतंत्र होना सक्षम था। क्या 3 क्लोन बनाने से बचने का कोई तरीका है?
  3. क्या स्टॉपइटरेशन अपवाद के बगल में अपवाद और फिर इसे फिर से उठाने का कोई बेहतर तरीका है? मैं इसे पकड़ने के लिए प्रेरित नहीं हूं और इसे बुलबुला करने देता हूं।

धन्यवाद! -रेमंड

+1

संबंधित: http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python http://stackoverflow.com/प्रश्न/434287/सबसे-पाइथोनिक-वे-टू-इटरेट-ओवर-ए-लिस्ट-इन -ंक्स http://stackoverflow.com/questions/1335392/iteration-over-list-slices http : //stackoverflow.com/questions/760753/iterate-over-a-python-sequence-in-multiples-of-n – jfs

उत्तर

4

आप इसका उपयोग क्यों नहीं कर रहे हैं?

def grouper(page_size, iterable): 
    page= [] 
    for item in iterable: 
     page.append(item) 
     if len(page) == page_size: 
      yield page 
      page= [] 
    yield page 

"प्रत्येक पृष्ठ स्वयं पेज_साइज के साथ एक पुनरावर्तक होगा" आइटम। प्रत्येक पृष्ठ आइटम की एक साधारण सूची है, जो पुनरावर्तनीय है।ऑब्जेक्ट के बजाए इटेटरेटर उत्पन्न करने के लिए आप yield iter(page) का उपयोग कर सकते हैं, लेकिन मुझे नहीं लगता कि यह कुछ भी कैसे सुधारता है।

यह अंत में एक मानक StopIteration फेंकता है।

आप और क्या चाहते हैं?

+0

मेरे प्रश्न का उत्तर देने और इटरेटर के माध्यम से बस लूप के बारे में सोचने का एक अच्छा तरीका प्रदान करने के लिए धन्यवाद। मुझे लगता है कि एक छोटी सी त्रुटि है - क्या आप आइटम को पृष्ठ पर जोड़ना चाहते थे - जैसा कि: डीफ़ ग्रूपर (पेज_साइज, इटेरिएबल): पृष्ठ = [] आइटम में पुन: प्रयोज्य: यदि लेन (पेज) == पेज_साइज: उपज पृष्ठ पृष्ठ = [] अन्य: पेज.एपेंड (आइटम) उपज पृष्ठ –

+0

@ रेमंडी: दरअसल, एक बेहतर तरीका है। आपका संस्करण एक बड़ा बंदरगाह है। कोशिश करें और देखें कि यह एक आइटम छोड़ देता है। –

+0

@ एसएलॉट - हाँ, ज़ाहिर है, मैंने अपना पेज रखा है। गलत जगह पर (आइटम)। सुधारों के लिए धन्यवाद। मैं अभी भी सीख रहा हूं कि जब itertools मदद कर सकता है और इसकी आवश्यकता नहीं होती है। पेशकश करने के लिए कोई दिशानिर्देश? –

7

itertools recipes में grouper() पर देखें।

+0

व्यंजनों को इंगित करने के लिए धन्यवाद। मैं grouper का उपयोग कर देख सकते हैं क्योंकि यह मेरे पेजर की तरह व्यवहार करने के लिए नुस्खा कुशल और अनुकूल है। मैं अभी भी उत्सुक हूं कि पेजर के रूप में यह खड़ा है या नहीं - या मुझे इसे एक ग्रूपर-जैसी दृष्टिकोण के लिए छोड़ देना चाहिए। –

0

ग्रूपर() के लिए इटर्टोल्स रेसिपी के सूचक के आधार पर, मैं पेजर की नकल करने के लिए ग्रूपर() के निम्नलिखित अनुकूलन के साथ आया था। मैं किसी भी कोई भी परिणाम को फ़िल्टर करना चाहते थे और (हालांकि मुझे लगता है थोड़ा लाभ हो सकता है कि इस रूपांतरण करने में) के बजाय एक टपल से पुनरावर्तक वापस जाने के लिए

# based on http://docs.python.org/library/itertools.html#recipes 
def grouper2(n, iterable, fillvalue=None): 
    args = [iter(iterable)] * n 
    for item in izip_longest(fillvalue=fillvalue, *args): 
     yield iter(filter(None,item)) 

मैं पर कैसे क्या मैं कर सकते हैं प्रतिक्रिया का स्वागत करते चाहते हैं चाहता था इस कोड को बेहतर बनाने के लिए करें।

2

मैं इस तरह यह करना चाहते हैं:

def pager(iterable, page_size): 
    args = [iter(iterable)] * page_size 
    fillvalue = object() 
    for group in izip_longest(fillvalue=fillvalue, *args): 
     yield (elem for elem in group if elem is not fillvalue) 

इस तरह, None एक वैध मान जो इटरेटर बाहर थूक हो सकता है। केवल एकल ऑब्जेक्ट fillvalue फ़िल्टर किया गया, और यह संभवतः पुनरावृत्त का तत्व नहीं हो सकता है।

+0

धन्यवाद, मैट। आपने मुझे एहसास दिलाया कि मैं दोनों को इटेटरेटर से कानूनी मूल्य होने की अनुमति नहीं दे रहा था और मैं भरने के लिए जिम्मेदार नहीं था। –

0
def group_by(iterable, size): 
    """Group an iterable into lists that don't exceed the size given. 

    >>> group_by([1,2,3,4,5], 2) 
    [[1, 2], [3, 4], [5]] 

    """ 
    sublist = [] 

    for index, item in enumerate(iterable): 
     if index > 0 and index % size == 0: 
      yield sublist 
      sublist = [] 

     sublist.append(item) 

    if sublist: 
     yield sublist 
संबंधित मुद्दे