关于python:pre-compute len(range(start,stop,step))。

Pre-compute len(range(start, stop,step) )

在实际调用之前,如何计算调用range(start, stop, step)所产生的元素数?

上下文是我正在实现一个对象的切片索引

1
2
3
4
5
6
7
8
def __init__(self, impl_object):
   self.impl=impl_object # the object that actually holds (or generates) an array of values
def __getitem__(self, key):
    if isinstance(key, slice):
         (start,stop,step)=key.indices( self.impl.numValues() )
         # It would be nice to know how many items I'm dealing with
         # here
    ...snip...

我已经说服自己,对于step>0len(range(start,stop,step))==(start-stop+step-1)/step

但我不知道如何将其概括为否定步骤。

编辑:我要求(强烈建议)解决方案需要花费O(1)时间。


最简单的方法是

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

xrange.__len__计算它将yield计算的元素数,而不在内存中构造范围。


如果您的startstopstepxrange的特定于实现的限制一致(例如cpython 2.x要求它们是"短的"python整数),您可以通过调用来获取range(start, stop, step)将包含的值的数量:

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

在引擎盖下,xrange()调用返回xrange对象:

XRange objects have very little behavior: they only support indexing,
iteration, and the len() function.

len()调用为o(1),因为xrange类型根据传递的参数进行计算实现__len__方法,len()发现传递给它的对象实现__len__并调用它来获取长度。

如果你的startstopstep可能不适用于xrange(),这里有一个功能(在黑客新闻讨论的帮助下实现xrange的博客文章值得称赞):

1
2
def len_range(start, stop, step):
    return max(0, (stop - start) // step + bool((stop - start) % step))


尝试使用abs(步骤)而不是步骤。