我使用下面的代码为英文字母创建了一个
itertools
循环,
lowercase_letters_cycle = itertools.cycle(string.ascii_lowercase)
如果我在此迭代器对象上运行
for
循环,第一次迭代会给我“a”作为输出,因为循环从“a”开始。我怎样才能使循环从我选择的任何字母开始?
一种有效的方法是,
def start_cycle(letter):
lowercase_letters_cycle = itertools.cycle(lowercase_letters)
letter_index = lowercase_letters.index(letter)
index = 0
while True:
if index == letter_index:
break
letter = next(lowercase_letters_cycle)
index += 1
return lowercase_letters_cycle
但是有没有更短的方法?
itertools
文档提供了一个食谱,用于使用迭代器中的多个项目。
from itertools import islice
import collections
def consume(iterator, n=None):
"Advance the iterator n-steps ahead. If n is None, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)
因此,您创建了循环,然后在继续之前消耗了一些它。
lowercase_letters_cycle = itertools.cycle(string.ascii_lowercase)
consume(lowercase_letters_cycle, ord('n') - ord('a'))
assert next(lowercase_letters_cycle) == 'n')
同样的
consume
也可以从第三方more-itertools
包获得。
您可以组合
islice
模块中的 cycle
和 itertools
,如下所示:
import string
import itertools
my_it = itertools.islice(itertools.cycle(string.ascii_lowercase), 3, None)
它将产生
d
(前 3 个字符之后的字符),然后是 e
,....,然后是 z
,然后是 a
,然后是 b
,依此类推。您可以将第二个参数中的数字更改为 islice
以从不同的字母开始。
您可以对输入列表进行切片以从您选择的索引开始。
offset = 10
lowercase_letters = list(string.ascii_lowercase)
# offset_index to end + start to offset_index-1
offset_letters = lowercase_letters[offset:] + lowercase_letters[:offset]
offset_letters_cycle = itertools.cycle(offset_letters)
那么,
for i in range(10):
print(next(offset_letters_cycle), end=" ")
打印:
k l m n o p q r s t
import string
from itertools import cycle, dropwhile
def start_cycle(letter):
return dropwhile(lambda x: x!= letter, cycle(string.ascii_lowercase))
itertools.dropwhile
会将可迭代的结果提供给其哨兵函数 - 在本例中为 lambda x: x != letter
,并将“吞噬”结果,直到函数第一次返回 False
。那时
该函数不再被调用,并且可迭代继续进行,产生任何
进一步的价值。
另外,请注意,无需将
ascii_lowercase
转换为列表,
因为字符串已经是可迭代的了。
请记住,如果传递的字符不是 ascii_lowercase,这将陷入 100% CPU 的无限循环。最好用支票来守护:
def start_cycle(letter):
if letter not in string.ascii_lowercase:
raise ValueError()
return dropwhile(lambda x: x!= letter, cycle(string.ascii_lowercase))
如果您只想从某个特定点开始浏览列表,您可以这样做:
my_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
start_index = 4
for i in my_list[start_index:]+my_list[:start_index]:
print(i)