Python: 如何在不创建范围的情况下计算范围的长度?

Python: How to calculate the length of a range without creating the range?

我需要计算一个范围的长度,但最好不要创建范围,(希望会更快并且使用更少的内存。这很重要,因为这个函数会被调用很多次)。长度用于设置扩展切片。

目前我已经尝试过:

int_div = lambda n, d: (n + d // 2) // d

def range_len(start, stop, step):
    return int_div(stop - start, step)

但在某些情况下,例如range_len(9, 100, 3) 正确答案是31时它给出30。我觉得这应该很简单,我做错了什么?

它给出 30,因为当您希望它始终四舍五入时,您的整数除法会四舍五入到最接近的整数。我不知道它有多快,但我只是使用 math.ceil 和浮点数除法。

在Python2中,可以使用xrange。在Python3中,可以使用range。在两者中,它们 return xrange/range 对象而不是生成整个列表。

Python 2

return len(xrange(start, stop, step))

Python 3

return len(range(start, stop, step))

来自xrange 帮助(在Python 2 解释器类型help(xrange)):

class xrange(object)  
|  xrange([start,] stop[, step]) -> xrange object  
|  
|  Like range(), but instead of returning a list, returns an object that   
| generates the numbers in the range on demand.  For looping, this is  
|  slightly faster than range() and more memory efficient.

range 中的帮助 Python 3:

class range(object)  
 |  range(stop) -> range object  
 |  range(start, stop[, step]) -> range object  
 |  
 |  Return an object that produces a sequence of integers from start (inclusive)  
 |  to stop (exclusive) by step.  range(i, j) produces i, i+1, i+2, ..., j-1.  
 |  start defaults to 0, and stop is omitted!  range(4) produces 0, 1, 2, 3.  
 |  These are exactly the valid indices for a list of 4 elements.  
 |  When step is given, it specifies the increment (or decrement).

创建 xrange/range 对象比创建关联列表的长度更快且内存效率更高。

使用此方法计算从 0 到 1000000 的范围花费了我的 PC 大约 0.000004291534423828125 秒。

您可以使用这个公式:(end - start - 1) // step + 1

def calc_length(start, end, step):
    return (end - start - 1) // step + 1

for i in range(start, end):
    calculated = calc_length(start, i, step)
    empirical = len(range(start, i, step))

    assert calculated == empirical, "{} {}".format(calculated, empirical)