【问题标题】:How to make a for loop either increasing or decreasing?如何使for循环增加或减少?
【发布时间】:2015-09-29 11:55:16
【问题描述】:

我必须在两个值之间循环,有时第一个值小于第二个值,有时第一个值大于第二个值(我正在处理网格内的两个单元格,第一个单元格可以在第二个的左边,反之亦然)。

使用 Python,我可以指定一个 for 循环是否必须减少或增加其值,但结果是这样的:

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

还有更多的“pythonic”来获得这个吗?

【问题讨论】:

  • 你可以这样做:for n in range(x, y, -1 if y &lt; x else 1):。它与您的代码基本相同
  • 注意,使用step作为-1与从小到大循环是不一样的!
  • @tobias_k 感谢您强调它:您在我的代码中发现了一个错误! :-)

标签: python for-loop


【解决方案1】:

请注意,使用step=-1与从较小值到较大值的范围相同!

>>> range(3, 7, 1)
[3, 4, 5, 6]
>>> range(7, 3, -1)
[7, 6, 5, 4]

第一个是从 3 到 6,后一个是从 4 到 7。

如果这仍然是您想要的,另一种方法是使用or

>>> 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) -> ~235µs 1000 对
  • x, y = (x, y) if x &lt; y else (y, x) -> 1000 对约 75µs

因此,三元运算符是最快的,但在大多数情况下,与其他代码(创建范围等)相比,它可能并不重要。

【讨论】:

  • 您可以使用range(*((x, y) if x &lt; y else (y, x))) 而不是调用sorted() 函数。
  • @martineau 啊,是的,这是除了 sorted 和 min/max 之外的另一种可能性。不容易决定哪个是最不可怕的......恕我直言,理解/解析有点困难,但从性能的角度来看,你的可能是最快的,但这只有在非常频繁地执行时才有意义。
  • sorted() 绝对是最易读的,而且可能在 99.9% 的情况下都很好。正是因为我的 C 语言背景,我才开始思考三元表达式,以避免调用函数只是为了对两个项目进行排序。
  • @martineau 我同意你的看法;我多次使用这个 for 循环,我不想调用函数,因为 python 不支持内联(我不能使用 PyPy)。
【解决方案2】:

我猜你可以这样做:

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

你的方式已经很pythonic了;)

编辑:@wap26 建议的更短方式:

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

【讨论】:

  • 索引集是正确的,但方向始终是递增顺序。
  • 稍微紧凑一点:xrange(*sorted((x,y)))
  • 我会修改不清楚的问题。 I have to loop between two values where sometimes the first value is lesser that the second and some other times the first is greater than the second
【解决方案3】:

与您的代码没有太大区别,但您可以使用它来计算 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]

【讨论】:

    猜你喜欢
    • 2016-02-18
    • 1970-01-01
    • 2023-04-09
    • 2011-02-06
    • 2022-12-04
    • 2012-09-30
    • 2016-10-13
    • 1970-01-01
    • 2014-09-10
    相关资源
    最近更新 更多