2010-09-19 19 views
7

Quiero ser capaz de tomar una secuencia como:¿Es así como paginas, o hay un algoritmo mejor?

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

utilizar una función como:

my_paginated_sequence = get_rows(my_sequence, 3) 

Para obtener:

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

Esto es lo que me ocurrió por simplemente pensando en ello:

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 
+2

@Noon - thx, no pensé en agregar eso. Además, ¿eres un ninja por casualidad? – orokusaki

+0

posible duplicado de [¿Rendimiento de múltiples objetos a la vez desde un objeto iterable?] (Http://stackoverflow.com/questions/2202461/yield-multiple-objects-at-a-time-from-an-iterable-object) –

+0

posible duplicado de [¿Cómo se divide una lista en trozos de igual tamaño en Python?] (Http://stackoverflow.com/q/312443/54262) –

Respuesta

11

Si usted sabe que tiene una secuencia que se puede rebanar (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 necesita absolutamente una lista como resultado, usará list(getrows_byslice(seq, 3)) o similar, por supuesto.

Si lo que empezar es un iterable genérica, la itertools recipes ofrecer ayuda con la receta ... 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 list en esto si una lista es lo tu quieres, por supuesto).

Dado que realmente desea truncar la última tupla en lugar de rellenarla, deberá "recortar" los valores de relleno finales de la última tupla.

+0

vea lo que quiero decir sobre Jedi. Siento que nunca podré hacer cosas así directamente de mi cerebro. ¿Alguna vez te sientes así en el día? – orokusaki

+0

@orokusaki, por supuesto, pero luego comencé a leer los documentos (recuerde que la función 'mero 'se cita directamente de los documentos! -). –

+1

Además, estoy hablando con mi hermano por teléfono sobre lo útil que es para la comunidad de Python en general. Ambos nos preguntamos, ¿qué es lo que impulsa tu entusiasmo para ayudar a otros?Espero que algún día pueda ser como tú sobre estas cosas, o lo que sea que esté haciendo en el futuro. – orokusaki

0

Si usted está buscando para la lista hacia arriba comprensión, esto va a hacer 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']] 
6

Esta versión funciona con cualquier (posiblemente perezoso y no se puede rebanar) iterable y produce una pereza iterable (en otras palabras, es un generador y funciona con todos los tipos de secuencias, incluyendo 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]] 
1

La función grouper en los itertools docs es inteligente y concisa; el único problema es que podrías necesitar recortar los resultados, como 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 puede hacerse mucho más simple. Esto funciona para todos los casos que puedo 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 
Cuestiones relacionadas