Это как вы разбиваете страницы, или есть лучший алгоритм?
Я хочу иметь возможность принять последовательность, как:
my_sequence = ['foo', 'bar', 'baz', 'spam', 'eggs', 'cheese', 'yogurt']
Используйте функцию как:
my_paginated_sequence = get_rows(my_sequence, 3)
Получить:
[['foo', 'bar', 'baz'], ['spam', 'eggs', 'cheese'], ['yogurt']]
Вот что я придумал, просто подумав:
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
4 ответа
Если вы знаете, что у вас есть срезаемая последовательность (список или кортеж),
def getrows_byslice(seq, rowlen):
for start in xrange(0, len(seq), rowlen):
yield seq[start:start+rowlen]
Это, конечно, генератор, поэтому, если вам абсолютно необходим список в результате, вы будете использовать list(getrows_byslice(seq, 3))
или тому подобное, конечно.
Если то, с чего вы начинаете, является универсальным итерируемым, то рецепты itertools помогут с 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)
(опять же, вам нужно позвонить list
на это, если список это то, что вы хотите, конечно).
Поскольку вы на самом деле хотите, чтобы последний кортеж был обрезан, а не заполнен, вам необходимо "обрезать" конечные значения заполнения из самого последнего кортежа.
Эта версия работает с любыми (возможно, ленивыми и неслайсинговыми) итерациями и создает ленивые итерации (другими словами, это генератор и работает со всеми типами последовательностей, включая другие генераторы):
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
Некоторые примеры:
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]]
grouper
функция в itertools
документы умны и лаконичны; единственная проблема в том, что вам, возможно, придется урезать результаты, как указал Алекс Мартелли. Я был бы склонен к решению в соответствии с ответом Михаила Марчика, хотя я не понимаю, почему это нельзя сделать намного проще. Это работает для всех случаев, которые я могу представить:
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
Если вы ищете четкое понимание списка, это сделает работу:
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']]