2017-09-08 3 views
0

J'essaye de créer une fonction qui accepte un itérateur python et renvoie un itérateur d'itérateurs, chaque élément étant un ensemble d'éléments de taille fixe provenant de l'itérateur d'origine. En d'autres termes:Pagination de l'itérateur en Python

paginate([a, b, c, d], 2) -> [[a,b],[c,d]] 

Mon code, travaux jusqu'à présent, mais renvoie une page de longueur nulle si la longueur du iterator est divisible par la taille de la page.

def paginate(iterator, pageSize): 
    hasMore = True 

    def pageIter(): 
     print (1) 
     try: 
      for _ in range(pageSize): 
       yield next(iterator) 
     except StopIteration as e: 
      nonlocal hasMore 
      hasMore = False 
      raise e 

    def pager(): 
      while hasMore: 
       yield pageIter() 
       if not hasMore: 
        raise StopIteration() 

    return pager() 

Je sais que itertools a une recette, mais ce code semble remplir des pages incomplètes avec None s.

Répondre

1

Ce qui suit devrait fonctionner avec tous les iterables, pas de listes juste:

class Paginator: 
    def __init__(self, iterable, page_len=3): 
     self.iterable = iterable 
     self.page_len = page_len 

    def __iter__(self): 
     page = [] 
     for i in self.iterable: 
      page.append(i) 
      if len(page) == self.page_len: 
       yield page 
       page = [] 
     if page: 
      yield page 

p = Paginator([1, 2, 3, 4, 5, 6, 7], 3) 
for i in p: 
    print(i) 

Sortie:

[1, 2, 3] 
[4, 5, 6] 
[7] 
1

Vous pouvez utiliser la recette take de itertools:

def take(n, iterable): 
    "Return first n items of the iterable as a list" 
    return list(islice(iterable, n)) 

Et puis :

def unchain(iterable, n): 
    iterable = iter(iterable) 
    while True: 
     result = take(n, iterable) 
     if result: 
      yield result 
     else: 
      raise StopIteration 

>>> list(unchain(['a', 'b', 'c', 'd'], 2)) 
[['a', 'b'], ['c', 'd']] 
>>> list(unchain(['a', 'b', 'c', 'd', 'e'], 2)) 
[['a', 'b'], ['c', 'd'], ['e']]