用于计数器的python循环?

时间:2018-06-10 18:18:19

标签: python for-loop

如何使用计数器创建for循环?我有一个列表,我想在每个n元素之后读取一个元素。我最初这样做了

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

但正如预期的那样,它会打印每个元素而不是每个第n个元素,解决这个问题的Python方法是什么?

4 个答案:

答案 0 :(得分:2)

使用itertools.islice() object将迭代限制为每个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字节码步骤来进行额外的测试或索引操作。

如果需要以这种方式选择项目的索引,请通过包装iterable来重新添加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

因此,对于100万个输入和1000个测试,enumerate()方法花费了 16次islice()版本和list(enumerate(...))[::n]版本一样多的时间复制和切片操作花费了将近3分钟来运行1000次测试,执行时间几乎<强> 50倍。不要使用那个选项!

答案 1 :(得分:2)

我不确定这种价值是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

答案 2 :(得分:0)

只需使用范围:

for i in range(0, size, n):
    print (i)

答案 3 :(得分:0)

enumerate返回一系列看起来像(index, value)

的元组

说出您的列表是my_list。你可以做点什么

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

这是向for循环添加索引的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)

速度快,内存效率高,但需要导入。当然,它来自标准库,但如果您正在为小型设备编写代码,可能它不可用。