Используйте itertools.islice()
объект , чтобы ограничить итерацию каждым n
-ым объектом, это как минимум в два раза быстрее, чем любое другое предлагаемое решение:
from itertools import islice
n = 5
for ob in islice(iterable, None, None, n):
print(ob)
Приведенное выше эффективно создает каждый 5-й объект, начиная с с первого:
>>> from itertools import islice
>>> from string import ascii_uppercase as iterable
>>> n = 5
>>> for ob in islice(iterable, None, None, n):
... print(ob)
...
A
F
K
P
U
Z
Замените первый None
на n - 1
, если вы хотите перейти кn
ый объект, который будет использоваться первым:
>>> for ob in islice(iterable, n - 1, None, n):
... print(ob)
...
E
J
O
T
Y
Для достижения этой цели не создается копия входной последовательности, поэтому для получения результатов не требуется дополнительная память или время.И взятие каждого n
-го объекта выполняется более эффективно, чем когда-либо мог бы выполнить тест модуля %
с индексом из enumerate()
, или использование range()
для генерации индекса.Это связано с тем, что для выполнения дополнительных тестов или операций с индексами не требуется никаких дополнительных шагов байт-кода Python.
Если вам также необходимо , чтобы индекс элементов был выбран таким образом, добавьте enumerate()
назадоборачивая итерацию:
>>> for i, ob in islice(enumerate(iterable), n - 1, None, n):
... print(i, ob)
...
4 E
9 J
14 O
19 T
24 Y
islice()
превосходит любое другое решение, если вам нужна скорость:
>>> from timeit import timeit
>>> from itertools import islice
>>> import random
>>> testdata = [random.randrange(1000) for _ in range(1000000)] # 1 million random numbers
>>> def islice_loop(it):
... for ob in islice(it, None, None, 5): pass
...
>>> def range_loop(it):
... for i in range(0, len(it), 5): ob = it[i]
...
>>> def slice_loop(it):
... for ob in it[::5]: pass
...
>>> def enumerate_test_loop(it):
... for i, ob in enumerate(it):
... if i % 5 == 0: pass
...
>>> def enumerate_list_slice_loop(it):
... for i, ob in list(enumerate(it))[::5]: pass
...
>>> timeit('tf(t)', 'from __main__ import testdata as t, islice_loop as tf', number=1000)
4.194277995004086
>>> timeit('tf(t)', 'from __main__ import testdata as t, range_loop as tf', number=1000)
11.904250939987833
>>> timeit('tf(t)', 'from __main__ import testdata as t, slice_loop as tf', number=1000)
8.32347785399179
>>> timeit('tf(t)', 'from __main__ import testdata as t, enumerate_list_slice_loop as tf', number=1000)
198.1711291699903
Итак, для 1 миллиона входов и 1000 тестов,enumerate()
подход занял в шестнадцать раз столько же времени, сколько версия islice()
, а операция list(enumerate(...))[::n]
копирование-и-фрагмент заняла почти 3 минуты для запуска 1000 тестов, тактирование почти в пятьдесят раз медленнее времени выполнения .Никогда не используйте эту опцию!