Я пытаюсь написать функцию Haskel 'splitEvery' в Python. Вот определение:
splitEvery :: Int -> [e] -> [[e]]
@'splitEvery' [email protected] splits a list into length-n pieces. The last
piece will be shorter if @[email protected] does not evenly divide the length of
the list.
Основная версия этого прекрасно работает, но мне нужна версия, которая работает с генераторными выражениями, списками и итераторами. И, если в качестве входа есть генератор, он должен возвращать генератор в качестве выхода!
Испытания
# should not enter infinite loop with generators or lists
splitEvery(itertools.count(), 10)
splitEvery(range(1000), 10)
# last piece must be shorter if n does not evenly divide
assert splitEvery(5, range(9)) == [[0, 1, 2, 3, 4], [5, 6, 7, 8]]
# should give same correct results with generators
tmp = itertools.islice(itertools.count(), 10)
assert list(splitEvery(5, tmp)) == [[0, 1, 2, 3, 4], [5, 6, 7, 8]]
Текущая реализация
Вот код, который у меня есть, но он не работает с простым списком.
def splitEvery_1(n, iterable):
res = list(itertools.islice(iterable, n))
while len(res) != 0:
yield res
res = list(itertools.islice(iterable, n))
Это не работает с выражением генератора (благодаря jellybean для его исправления):
def splitEvery_2(n, iterable):
return [iterable[i:i+n] for i in range(0, len(iterable), n)]
Должен быть простой фрагмент кода, который выполняет разделение. Я знаю, что у меня могут быть разные функции, но, похоже, это должно быть и легко. Я, вероятно, застрял на несущественной проблеме, но это действительно меня подслушивает.
Он похож на grouper из http://docs.python.org/library/itertools.html#itertools.groupby, но я не хочу, чтобы он заполнял дополнительные значения.
def grouper(n, iterable, fillvalue=None):
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
Он упоминает метод, который усекает последнее значение. Это не то, что я хочу.
Порядок следования итераций слева направо гарантирован. Это делает возможным идиому для кластеризации рядов данных в n-длинные группы с использованием izip (* [iter (s)] * n).
list(izip(*[iter(range(9))]*5)) == [[0, 1, 2, 3, 4]]
# should be [[0, 1, 2, 3, 4], [5, 6, 7, 8]]