У меня есть функция Python, которая берет список и возвращает генератор, дающий 2-кортежи каждой смежной пары, например
>>> list(pairs([1, 2, 3, 4]))
[(1, 2), (2, 3), (3, 4)]
Я рассмотрел реализацию с использованием 2 срезов:
def pairs(xs):
for p in zip(xs[:-1], xs[1:]):
yield p
и один написан в более процедурном стиле:
def pairs(xs):
last = object()
dummy = last
for x in xs:
if last is not dummy:
yield last,x
last = x
Тестирование с использованием range(2 ** 15)
в качестве ввода дает следующие моменты (вы можете найти мой тестовый код и вывести здесь):
2 slices: 100 loops, best of 3: 4.23 msec per loop
0 slices: 100 loops, best of 3: 5.68 msec per loop
Частью хита производительности для sliceless-реализации является сравнение в цикле (if last is not dummy
). Удаление этого (неверный вывод) улучшает его производительность, но оно все же медленнее, чем реализация zip-a-pair-of-slices:
2 slices: 100 loops, best of 3: 4.48 msec per loop
0 slices: 100 loops, best of 3: 5.2 msec per loop
Итак, я в тупике. Зачем сжимать два среза, эффективно повторяя их по списку дважды параллельно, быстрее, чем повторять один раз, обновляя last
и x
, когда вы идете?
ИЗМЕНИТЬ
Дан Ленски предложил третью реализацию:
def pairs(xs):
for ii in range(1,len(xs)):
yield xs[ii-1], xs[ii]
Здесь его сравнение с другими реализациями:
2 slices: 100 loops, best of 3: 4.37 msec per loop
0 slices: 100 loops, best of 3: 5.61 msec per loop
Lenski's: 100 loops, best of 3: 6.43 msec per loop
Это еще медленнее! Что меня озадачивает.
ИЗМЕНИТЬ 2:
ssm предложил, используя itertools.izip
вместо zip
, и он даже быстрее, чем zip
:
2 slices, izip: 100 loops, best of 3: 3.68 msec per loop
Итак, izip
- победитель! Но по-прежнему трудно проверить причины.