Идеальное решение этой проблемы работает с итераторами (а не только с последовательностями). Это также должно быть быстро.
Это решение, предоставляемое документацией для 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)
Используя ipython's %timeit
на моем MacBook Air, я получаю 47,5 нас за цикл.
Тем не менее, это действительно не работает для меня, так как результаты дополняются до четных групп. Решение без дополнения немного сложнее. Наиболее наивное решение может быть:
def grouper(size, iterable):
i = iter(iterable)
while True:
out = []
try:
for _ in range(size):
out.append(i.next())
except StopIteration:
yield out
break
yield out
Простой, но довольно медленный: 693 нас за цикл
Лучшее решение, которое я мог придумать, использует islice
для внутреннего цикла:
def grouper(size, iterable):
it = iter(iterable)
while True:
group = tuple(itertools.islice(it, None, size))
if not group:
break
yield group
С тем же набором данных я получаю 305 нас за цикл.
Невозможно получить чистое решение быстрее, чем это, я предлагаю следующее решение с одним важным предупреждением: если ваши входные данные содержат экземпляры filldata
, вы можете получить неправильный ответ.
def grouper(n, iterable, fillvalue=None):
#"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
for i in itertools.izip_longest(fillvalue=fillvalue, *args):
if tuple(i)[-1] == fillvalue:
yield tuple(v for v in i if v != fillvalue)
else:
yield i
Мне действительно не нравится этот ответ, но он значительно быстрее. 124 доллара США за цикл