¿Es así como paginas, o hay un algoritmo mejor?

Quiero poder tomar una secuencia como:

my_sequence = ['foo', 'bar', 'baz', 'spam', 'eggs', 'cheese', 'yogurt'] 

Usa una función como:

 my_paginated_sequence = get_rows(my_sequence, 3) 

Llegar:

 [['foo', 'bar', 'baz'], ['spam', 'eggs', 'cheese'], ['yogurt']] 

Esto es lo que se me ocurrió con solo pensarlo:

 def get_rows(sequence, num): count = 1 rows = list() cols = list() for item in sequence: if count == num: cols.append(item) rows.append(cols) cols = list() count = 1 else: cols.append(item) count += 1 if count > 0: rows.append(cols) return rows 

    Si sabe que tiene una secuencia que se puede cortar (lista o tupla),

     def getrows_byslice(seq, rowlen): for start in xrange(0, len(seq), rowlen): yield seq[start:start+rowlen] 

    Por supuesto, esto es un generador, por lo que si absolutamente necesita una lista como resultado, usará list(getrows_byslice(seq, 3)) o similar, por supuesto.

    Si lo que empiezas es un iterable genérico, las recetas de itertools ofrecen ayuda con la receta del grouper

     import itertools def grouper(n, iterable, fillvalue=None): "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" args = [iter(iterable)] * n return itertools.izip_longest(fillvalue=fillvalue, *args) 

    (de nuevo, tendrá que llamar a la list en este caso si una lista es lo que quiere, por supuesto).

    Ya que realmente desea que la última tupla se trunca en lugar de rellenarla, deberá “recortar” los valores de relleno finales de la última tupla.

    Esta versión funciona con cualquier iterable (posiblemente perezoso y no segmentable) y produce un iterable perezoso (en otras palabras, es un generador y funciona con todos los tipos de secuencias, incluidos otros generadores):

     import itertools def paginate(iterable, page_size): while True: i1, i2 = itertools.tee(iterable) iterable, page = (itertools.islice(i1, page_size, None), list(itertools.islice(i2, page_size))) if len(page) == 0: break yield page 

    Algunos ejemplos:

     In [61]: list(paginate(my_sequence, 3)) Out[61]: [['foo', 'bar', 'baz'], ['spam', 'eggs', 'cheese'], ['yogurt']] In [62]: list(paginate(xrange(10), 3)) Out[62]: [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]] 

    La función de itertools en los documentos de itertools es inteligente y concisa; El único problema es que es posible que deba recortar los resultados, como lo señaló Alex Martelli. Me inclinaría por una solución similar a la respuesta de Michał Marczyk, aunque no veo por qué eso no se puede hacer mucho más simple. Esto funciona para todos los casos que pueda concebir:

     import itertools def paginate(seq, page_size): i = iter(seq) while True: page = tuple(itertools.islice(i, 0, page_size)) if len(page): yield page else: return 

    Si está buscando una comprensión de lista directa, esto hará el trabajo:

     L = ['foo', 'bar', 'baz', 'spam', 'eggs', 'cheese', 'yogurt'] [L[i*3 : (i*3)+3] for i in range((len(L)/3)+1) if L[i*3 : (i*3)+3]] # [['foo', 'bar', 'baz'], ['spam', 'eggs', 'cheese'], ['yogurt']] L = ['foo', 'bar', 'baz', 'spam', 'eggs', 'cheese'] # [['foo', 'bar', 'baz'], ['spam', 'eggs', 'cheese']]