英文:
for each loop pyton - nested loop
问题
lyrics = ["我想要自由", "我想要自由", "我想要自由", "是的,我想要自由"]
number_of_lines = 6
for line in lyrics:
print(line)
英文:
lyrics = ["I want to break free", "I want to break free",
"I want to break free", "yes, I want to break free"]
number_of_lines = 6
I am trying to create a loop that prints as many lines as many number_of_lines. In this specific example I basically need to loop IN lyrics 1.5 times to print the whole list (4 lines) and then the first 2 again to get to 6 = number of lines. How do you do it exactly?
thanks much in advance
for line in lyrics:
print(line)
答案1
得分: 1
使用itertools.cycle
来重复列表的内容,直到获得所需数量的行数(使用itertools.islice
):
from itertools import cycle, islice
lyrics = ["I want to break free", "I want to break free",
"I want to break free", "yes, I want to break free"]
number_of_lines = 6
for line in islice(cycle(lyrics), 6):
print(line)
这会增加一些额外的内存开销。cycle
必须缓存它从迭代器中读取的值以便重复使用。当使用cycle
和大型列表时需要考虑这一点,但通常列表会很小。
问题在于cycle
会迭代其可迭代参数从中获取的迭代器,而迭代器背后的列表在调用next
之间可能会发生变化。例如:
from itertools import cycle
x = [1,2,3]
i = cycle(x)
next(i) # 输出 1
next(i) # 输出 2
x.clear()
next(i) # 不是3,输出 1
next(i) # 输出 2
next(i) # 输出 1
英文:
Use itertools.cycle
to repeat the contents of the list as often as necessary to obtain the desired number of lines (using itertools.islice
):
from itertools import cycle, islice
lyrics = ["I want to break free", "I want to break free",
"I want to break free", "yes, I want to break free"]
number_of_lines = 6
for line in islice(cycle(lyrics), 6):
print(line)
This incurs some additional memory overhead, though. cycle
has to cache the values it reads from its iterator in order to repeat them. Just something to keep in mind when using cycle
and large lists, but typically the lists will be small.
The issue is that cycle
iterates over an iterator it obtains from its iterable argument, and the list behind the iterator could change between calls to next
. For example,
>>> from itertools import cycle
>>> x = [1,2,3]
>>> i = cycle(x)
>>> next(i)
1
>>> next(i)
2
>>> x.clear()
>>> next(i) # Not 3
1
>>> next(i)
2
>>> next(i)
1
答案2
得分: 0
你可以使用模运算符如下所示:
lyrics = ["我想要自由", "我想要自由", "我想要自由", "是的,我想要自由"]
number_of_lines = 6
for i in range(number_of_lines):
print(lyrics[i%len(lyrics)])
输出:
我想要自由
我想要自由
我想要自由
是的,我想要自由
我想要自由
我想要自由
英文:
You could use the modulo operator as follows:
lyrics = ["I want to break free", "I want to break free", "I want to break free", "yes, I want to break free"]
number_of_lines = 6
for i in range(number_of_lines):
print(lyrics[i%len(lyrics)])
Output:
I want to break free
I want to break free
I want to break free
yes, I want to break free
I want to break free
I want to break free
答案3
得分: 0
另一个选项(也许更符合"Pythonic",因为它使用了取模运算符)是使用Python中的itertools模块中提供的cycle()
方法,代码如下:
lyrics = ["I want to break free", "I want to break free", "I want to break free", "yes, I want to break free"]
number_of_lines = 6
from itertools import cycle
line_in_lyrics_cycle = cycle(lyrics)
for _ in range(number_of_lines):
print(next(line_in_lyrics_cycle))
由于line_in_lyrics_cycle
是一个迭代器,您可以使用Python的next()
方法从中获取一行,无需在循环中使用range()
提供的索引值。这里的一个很好的副作用是,由于使用了next()
,您可以像阅读解释一样阅读代码,理解它的功能。
为了完整起见,这里是Kelly Bundy在评论中提出的代码,对应于其他答案中chepner使用itertools的方法:
from itertools import islice, chain, repeat
q, r = divmod(number_of_lines, len(lyrics))
fulls = chain.from_iterable(repeat(lyrics, q))
tail = islice(lyrics, r)
for line in chain(fulls, tail):
print(line)
这段代码在纯Python列表的术语中表达如下:
q, r = divmod(number_of_lines, len(lyrics))
lyrics_total = q * lyrics + lyrics[0:r]
for line in lyrics_total:
print(line)
特别是看看第一个版本的代码,它充分利用了itertools迭代器的全部优点,使得
print(next(line_in_lyrics_cycle))
完全消失了,深埋在真的很难理解的代码下面,你可能需要三倍的文本行来解释这段代码的作用、如何以及为什么这么做。
在这种情况下,Pingu提供的代码需要更少的解释,因为您只需要理解取模运算符%
的工作原理,而不必担心divmod
和/或itertools
。它之所以出色,是因为它的简洁性达到了循环的核心要点:
for i in range(number_of_lines):
print(lyrics[i % len(lyrics)])
英文:
Another option (maybe a bit more "Pythonic" as using the modulo operator) is to use the cycle()
method available in the with Python coming itertools module as follows:
lyrics = ["I want to break free", "I want to break free", "I want to break free", "yes, I want to break free"]
number_of_lines = 6
from itertools import cycle
line_in_lyrics_cycle = cycle(lyrics)
for _ in range(number_of_lines):
print( next(line_in_lyrics_cycle) )
And because line_in_lyrics_cycle
is an iterator you get a line out of it using the Python next()
method and don't need the index value provided in the loop by range()
. A nice side-effect here is that because of use of next()
you can read the code like you would read the explanation what it does.
For the sake of completeness here the code proposed by Kelly Bundy in comments to the other itertools using answer by chepner:
from itertools import islice, chain, repeat
q, r = divmod(number_of_lines, len(lyrics))
fulls = chain.from_iterable(repeat(lyrics, q))
tail = islice(lyrics, r)
for line in chain(fulls, tail):
print(line)
which does expressed in terms of Python list only:
q, r = divmod(number_of_lines, len(lyrics))
lyrics_total = q*lyrics+lyrics[0:r]
for line in lyrics_total:
print(line)
Looking especially at the first version of the code making full use of the itertools iterators the entire BEAUTY of
print( next(line_in_lyrics_cycle) )
is gone, buried so deep under the really hard to understand code, that you need probably three times the lines of text to explain what, how and why just this code.
In this context the code provided by Pingu needs much less explanations, because you only have to understand how the modulo %
operator works and must not worry about divmod
and/or itertools
.
It excels because of its shortness got down to the bare point of cycling which the modulo operator is all about:
for i in range(number_of_lines):
print(lyrics[i%len(lyrics)])
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论