如何编写一个for循环,使其可以递增或递减?

8

我需要在两个值之间循环,有时第一个值小于第二个值,有时第一个值大于第二个值(我正在处理网格中的两个单元格,第一个单元格可以在第二个单元格左侧或右侧)。

使用Python,我可以指定for循环是要递减还是递增其值,但结果会像这样:

step = 1
if y < x:
    step = -1
for n in range(x, y, step):
    pass

有没有更符合 Python 语言特色的方法来获取这个结果呢?


你可以这样写:for n in range(x, y, -1 if y < x else 1):。这本质上与你的代码相同。 - Markus Meskanen
2
请注意,使用步长为“-1”并不等同于从较小值循环到较大值! - tobias_k
@tobias_k 感谢你指出这个问题:你在我的代码中发现了一个错误! :-) - Andrea Iacono
3个回答

9
请注意,使用 step=-1 并不等同于从较大值到较小值的范围!
>>> range(3, 7, 1)
[3, 4, 5, 6]
>>> range(7, 3, -1)
[7, 6, 5, 4]

第一个是从3到6,后一个是从4到7。
如果这仍然是您想要的,另一种方法是使用"或":
>>> x, y = 7, 3
>>> range(x, y, x < y or -1)
[7, 6, 5, 4]

如果您想包括下标和上标,您需要偏移“to”索引:
>>> step = +1 if x < y else -1 # or use that 'or' expression
>>> range(x, y + step, step)
[7, 6, 5, 4, 3]

否则,您可以首先对值进行排序,使用minmaxsorted函数:
>>> x, y = sorted((x, y))
>>> range(x, y)
[3, 4, 5, 6]

或者一行代码:range(*sorted((x, y)))(虽然我认为这不太可读)。
我进行了一些时间分析,对1000个随机的x,y对进行排序(每种方法使用相同的对):
  • x,y = sorted((x,y)) -> 1000个对大约需要305µs
  • x,y = min(x,y),max(x,y) -> 1000个对大约需要235µs
  • x,y = (x,y) if x < y else (y,x) -> 1000个对大约需要75µs
所以三元运算符是最快的,但在大多数情况下,与其他代码(创建范围等)相比,它可能并不重要。

你可以使用 range(*((x, y) if x < y else (y, x))) 代替调用 sorted() 函数。 - martineau
@martineau 哦,是的,这是除了sorted和min/max之外的另一种可能性。很难决定哪个是最不可怕的... 在我看来,它可能更难理解/解析,但从性能角度来看,你的方法可能是最快的,但只有在真的非常频繁地执行时才会有影响。 - tobias_k
sorted() 绝对是最易读的,而且在99.9%的情况下都很好用。正是我在C语言背景下思考,才会想到使用三元表达式来避免调用函数来排序两个项目。 - martineau
1
@martineau 我同意你的观点;我经常使用这个for循环,而且我宁愿不调用函数,因为Python不支持内联(我不能使用PyPy)。 - Andrea Iacono

4
我想你可以这样做:

我猜你可以像这样做:

for n in xrange(min(x,y), max(x,y)):

你的方式已经非常符合Pythonic的写法了 ;)

编辑:@wap26建议的更简洁的方式:

for n in xrange(*sorted((x,y))):

1
索引集合是正确的,但方向总是递增顺序。 - wap26
1
稍微更紧凑一些:xrange(*sorted((x,y))) - wap26
我会修改这个不太清晰的问题。我需要在两个值之间循环,有时第一个值小于第二个值,有时第一个值大于第二个值。 - Cyrbil

1

这并不会对您的代码做出太多不同,但您可以使用它来计算step

range(x,y,(y-x)/abs(x-y))

例如:

In [10]: x,y = 5,10

In [11]: range(x,y,(y-x)/abs(x-y))
Out[11]: [5, 6, 7, 8, 9]

In [12]: x,y = 10,5

In [13]: range(x,y,(y-x)/abs(x-y))
Out[13]: [10, 9, 8, 7, 6]

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