【问题标题】:Python: How to calculate the length of a range without creating the range?Python:如何在不创建范围的情况下计算范围的长度?
【发布时间】:2015-10-28 14:44:31
【问题描述】:

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

现在我已经试过了:

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。我觉得这应该很简单,我做错了什么?

【问题讨论】:

  • @FirebladeDan 对不起,我不明白你的意思。你是说我应该这样做:range_len(start, stop, step) * step - 1 如果 step 大于 0? (我假设你不是,因为那是错误的,但我就是这么理解的)
  • 为什么不用 xrange?它有什么不同?
  • 对于它的价值,python3 中的range 实现了一个__len__,它只计算术语的数量(正是你在这里所做的)。所以在 python3 的 range 上调用 len 是 O(1)。
  • @NightShadeQueen 我正在使用 Python 2.7,但谢谢。
  • @NightShadeQueen:这很有趣,我认为 python 3 的 range 与 Python 2 的 xrange 完全相同。

标签: python list python-2.7 slice


【解决方案1】:

你可以使用这个公式:(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)

【讨论】:

  • 谢谢,这行得通,除了 range() 之外的所有解决方案似乎都具有相似的速度并且它们都可以工作,但我认为这个是最简单的。
  • @Kytuzian:它因否定步骤而失败,例如range(10, 0, -1)。你可以使用this implementation instead
  • @J.F.Sebastian 谢谢。我的程序中没有负面步骤,但我会保存它以防万一。
【解决方案2】:

在 Python 2 中,您可以使用 xrange。在 Python 3 中,您可以使用 range。在这两种情况下,它们都返回 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.

或 Python 3 中的 range 帮助:

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 的范围花了我的电脑大约 0.000004291534423828125 秒。

【讨论】:

  • 我已经想到了这一点,但我认为其他解决方案会更快。事实证明它们都非常相似(除了范围,它要慢得多)。 Python 2.7 在这里
  • ##清晰的解决方案##
【解决方案3】:

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

【讨论】:

  • 谢谢,这行得通,除了 range() 之外的所有解决方案似乎都具有相似的速度并且它们都可以工作。
猜你喜欢
  • 2018-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-18
  • 1970-01-01
  • 2013-07-01
  • 2019-08-21
相关资源
最近更新 更多