Python中的来回循环

24

我想创建一个无限循环,从0到100再从100到0(以此类推)并且只有在循环内部满足某些收敛准则时才停止,基本上是这样的:

for i in range(0, infinity):
    for j in range(0, 100, 1):
        print(j) # (in my case 100 lines of code)
    for j in range(100, 0, -1):
        print(j) # (same 100 lines of code as above)

有没有办法将循环j的两个for循环合并为一个,这样我就不必在循环内部两次编写相同的代码了?


4
这听起来是一个很好的函数使用案例,这样我就不必重复编写相同的代码了。 - DeepSpace
7
TypeError: unsupported operand type(s) for +: 'range' and 'range'。这个错误只能在Python 2中运行。意思是两个range对象不能直接相加。 - DeepSpace
是的,这只适用于Python 2。 - Phylogenesis
5
三个附注:range(100,0,-1) 实际上并不会以相反的方式产生 range(0, 100, 1)。如果你想从 0 到包含 99,然后从 99 回到 0,可以使用 range(99,-1,-1)range(100)range(0,100,1) 的缩写形式,最好使用它。而且,没有 range(0,正无穷) 语法,你可以使用 for i in itertools.count(): 创建一个无限计数器,或者使用 while True: 创建一个无限循环。 - Martijn Pieters
11个回答

43

使用itertoolschain方法。

import itertools
for i in range(0, infinity):
    for j in itertools.chain(range(0, 100, 1), range(100, 0, -1)):
        print(j) # (in my case 100 lines of code)
如@Chepner所建议,您可以使用itertools.cycle()来进行无限循环:
from itertools import cycle, chain

for i in cycle(chain(range(0, 100, 1), range(100, 0, -1))):
    ....

13
你可以加入 itertools.cycle,避免使用嵌套循环。翻译后代码如下:for i in itertools.cycle(chain(range(100), range(100, 0, -1))) - chepner
正如@MartijnPieters所评论的那样,它一次使用了太多的内存。 - N Chauhan
1
@damienfrancois:我不同意通用解包更好的说法。尝试使用range(10**6), range(10**6, -1, -1)这种技术,然后观察内存占用情况。 - Martijn Pieters
谢谢。我之前不知道itertools,它们很棒! - Irfan wani

18

除了其他答案,你还可以运用一些数学:

while(True):
    for i in range(200):
        if i > 100:
            i = 200 - i

9

以下是另一种可能性:

while notConverged:
    for i in xrange(-100, 101):
        print 100 - abs(i)

6
如果您有一组重复的代码,请使用函数来节省空间和精力:
def function(x, y, x, num_from_for_loop):
    # 100 lines of code 

while not condition:
    for i in range(1, 101):
        if condition:
            break
        function(x, y, z, i)
    for i in range(100, 0, -1):
        if condition:
            break
        function(x, y, z, i)

你甚至可以使用 while True

来实现。


+1... 我认为很多“哦,我知道一个itertools函数可以帮助!”的答案都忽略了大局。 - Sneftel
我同意,虽然老实说除了一些简单的函数外,我对itertools一无所知。 - N Chauhan

3
如果您使用的是Python 3.5+,则可以使用通用拆包功能:
for j in (*range(0, 100, 1), *range(100, 0, -1)):

在Python 3.5版本或之前,您可以使用itertools.chain

from itertools import chain

...

for j in chain(range(0, 100, 1), range(100, 0, -1)):

15
通用的解包方式会生成一个非常大的元组,并将所有整数都实例化(请记住,range()对象非常轻量级)。链式操作更好! - Martijn Pieters

3
up = True # since we want to go from 0 to 100 first

while True: #for infinite loop

    # For up == True we will print 0-->100 (0,100,1)
    # For up == False we will print 100-->0 (100,0,-1)


    start,stop,step = (0,100,1) if up else (100,0,-1)
    for i in range(start,stop,step):
        print(i)

    up = not up # if we have just printed from 0-->100 (ie up==True), we want to print 100-->0 next so make up False ie up = not up( True) 

    # up will help toggle, between 0-->100 and 100-->0

1
反转布尔值的专业技巧:up ^= True - wjandrea
@wjandrea 是的,谢谢你的评论。忘记添加一个附注了,我本来打算使用它,但后来想保持简单以防万一提问者是初学者。 - Tanmay jain

1
def up_down(lowest_value, highest_value):
    current = lowest_value
    delta = 1
    while True: # Begin infinite loop
        yield current
        current += delta
        if current <= lowest_value or current >= highest_value:
            delta *= -1 # Turn around when either limit is hit

这定义了一个生成器,只要您需要,它将继续产生值。例如:

>>> u = up_down(0, 10)
>>> count = 0
>>> for j in u:
    print(j) # for demonstration purposes
    count += 1 # your other 100 lines of code here
    if count >= 25: # your ending condition here
        break


0
1
2
3
4
5
6
7
8
9
10
9
8
7
6
5
4
3
2
1
0
1
2
3
4

1

我想知道是否可以不使用条件和枚举实现这种三角波振荡器。那么,下面是一种选项:

def oscillator(magnitude):
   i = 0
   x = y = -1
   double_magnitude = magnitude + magnitude

   while True:
       yield i
       x = (x + 1) * (1 - (x // (double_magnitude - 1)))  # instead of (x + 1) % double_magnitude
       y = (y + 1) * (1 - (y // (magnitude - 1)))         # instead of (y + 1) % magnitude
       difference = x - y                                 # difference ∈ {0, magnitude}
       derivative = (-1 * (difference > 0) + 1 * (difference == 0))
       i += derivative

这个想法是使用两个不同周期的锯齿波,相互减去。结果将是一个方波,其值为{0,magnitude}。然后我们只需分别用{-1,+1}替换{0,magnitude},以获得目标信号的导数值。
让我们看一个例子,其中:
o = oscillator(5)
[next(o) for _ in range(21)]

这将输出[0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 0]
如果允许使用abs(),可以简化代码。例如,下面的代码将输出与上述相同的结果:
[abs(5 - ((x + 5) % 10)) for x in range(21)]

0

这更像是对你问题的部分回答,而不是直接回答。但是你也可以使用三角函数及其振荡的概念来模拟一个“来回”循环。

如果我们有一个余弦函数,振幅为100,向左移并上移,使得 f(x) = 00 <= f(x) <= 100,那么我们可以使用公式 f(x) = 50(cos(x-pi)+1)(图表可在这里找到)。这个范围正好符合你的要求,并且会发生振荡,所以不需要取反任何值。

>>> from math import cos, pi
>>> f = lambda x: 50*(cos(x-pi)+1)
>>> f(0)
0.0
>>> f(pi/2)
50.0
>>> f(pi)
100.0
>>> f(3*pi/2)
50.0
>>> f(2*pi)
0.0

当然,问题在于该函数不容易给出整数值,因此它并没有那么有用 - 但这可能对未来的读者有用,其中三角函数可能对他们的情况有帮助。

0

我之前也遇到过类似的问题,想要创建一个无限三角波形式的值,但是又想跳过一些值。最终我使用了生成器(和其他人一样使用range函数)来解决:

def tri_wave(min, max, step=1):
    while True:
        yield from range(min, max, step)
        yield from range(max, min, -1 * step)

通过精心选择min、max和step的值(即均匀可除),

for value in tri_wave(0, 8, 2):
    print(value, end=", ")

我只获取了一次最小值和最大值,这也是我的目标:

...0, 2, 4, 6, 8, 6, 4, 2, 0, 2, 4, 6, 8, 6, 4...

当时我在使用Python 3.6。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接