цикл в питоне со счетчиком? - PullRequest
0 голосов
/ 10 июня 2018

Как создать цикл for со счетчиком?У меня есть список, и я хочу читать элемент после каждого n элементов.Сначала я сделал это

for i in enumerate(n):
    print(i)

Но, как и ожидалось, он печатает каждый элемент, а не каждый n-й элемент, как бы Python решил эту проблему?

Ответы [ 4 ]

0 голосов
/ 10 июня 2018

enumerate возвращает последовательность кортежей, которые выглядят как (index, value)

Скажем, ваш список my_list.Вы могли бы сделать что-то вроде

for index, value in enumerate(my_list):
    if index % n == 0: #it's an nth item
        print(value)

Это способ добавления индекса в цикл для python.

Некоторые альтернативы

Если вашЦель состоит в том, чтобы сделать что-то с элементами списка с помощью n, вот несколько альтернативных решений, которые не обязательно добавляют индекс к вашему циклу, но помогут вам достичь нужного результата:

Нарезка массива

Вы также можете использовать фрагмент массива с шагом

nth_elements = my_array[0::n]
for e in nth_elements:
    print(e)

Преимущество заключается в том, что теперь вы работаете с меньшим списком, за счет увеличения объема памяти и времени.сделать копию, но это может быть полезно, если вы выполняете несколько операций с ней.Это быстро писать и легко читать.

Диапазон

Вы можете сделать что-то похожее с функцией диапазона

for index in range(0, len(my_list), n):
    print(n)

Примечание: если вы используете python2, используйте xrangeявляется предпочтительным.

Это просто возвращает вам индекс, а не индекс и значение.Это быстро и эффективно для памяти.range (или xrange) ленив, и вы используете индекс непосредственно в массиве, поэтому вам не нужно прикасаться к каждому элементу.

Itertools

Если вам нужна ленивая последовательность, вы можете использовать itertools.Это может быть полезно, если подпоследовательность слишком велика, чтобы удобно помещаться в памяти.

from itertools import islice
for element in islice(my_list, 0, len(my_list), n):
    print(element)

Это быстро и эффективно использует память, но требует импорта.Конечно, это из стандартной библиотеки, но если вы пишете код для небольшого устройства, возможно, он недоступен.

0 голосов
/ 10 июня 2018

Используйте 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 тестов, тактирование почти в пятьдесят раз медленнее времени выполнения .Никогда не используйте эту опцию!

0 голосов
/ 10 июня 2018

Я не уверен, какое значение имеет n, но обычно есть следующие способы: (для меня n - это список)

for index, item in enumerate(n):
   if index % nth == 0: # If the output is not like you want, try doing (index + 1), or enumerate(n, start=1).
       print(item)

Другой способ может быть:

for index in range(0, len(n), nth): # Only work with sequences
   print(n[index]) # If the output is not like you want, try doing n[index + 1]

Или:

for item in n[::nth]: # Low perfomance and hight memory consumption warning!! Only work with sequences
    print(item)

Даже вы можете объединить первое с последним:

for i, item in list(enumerate(n))[::nth]: # Huge low perfomance warning!!!
    print(item)

Но я не уверен, что это имеет преимущество...

Кроме того, если вы хотите создать функцию, вы можете сделать что-то похожее на функцию enumerate:

def myEnumerate(sequence, start=0, jump=1):
    n = start
    j = start // Or j = 0, that is your decision.
    for elem in sequence:
        if j % jump == 0:
            yield n, elem
            n += 1
        j += 1

for index, item in myEnumerate(n, jump=1):
    print(item)

Лично я бы не стал делать это в последнюю очередь.,Я не уверен, почему, но это чувство.

Тест производительности

n = 'a b c d e f g h i j k l m n ñ o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 ! " · $ % & / ( ) = ? ¿ Ç ç } { [ ] ; : _ ¨ ^ * ` + ´ - . , º ª \ /'.split(" ")
nth = 3    
def a():
    for i, item in enumerate(n):
       if i % nth == 0:
           item       
def b():
    for item in range(0, len(n), nth):
       n[item]           
def c():
    for item in n[::nth]:
        item    
def d():
    for i, item in list(enumerate(n))[::nth]:
       if i % nth == 0:
           item    
def enumerates(sequence, start=0, jump=1):
    n = start
    j = start
    for elem in sequence:
        if j % jump == 0:
            yield n, elem
            n += 1
        j += 1            
def e():
    for i, item in enumerates(n, jump= nth):
        item    
if __name__ == '__main__':
    import timeit
    print(timeit.timeit("a()", setup="from __main__ import a")) # 10.556324407152305
    print(timeit.timeit("b()", setup="from __main__ import b")) # 2.7166204783010137
    print(timeit.timeit("c()", setup="from __main__ import c")) # 1.0285353306076601
    print(timeit.timeit("d()", setup="from __main__ import d")) # 8.283859051918608
    print(timeit.timeit("e()", setup="from __main__ import e")) # 14.91601851631981

Но если вы действительно ищете производительность, вы должны прочитать @ Martijn Pieters answer .

0 голосов
/ 10 июня 2018

Просто используйте диапазон:

for i in range(0, size, n):
    print (i)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...