4

问题的具体实例
我的 int 范围为 1-100。我想在此范围内生成 n 个总数,这些总数尽可能均匀分布,并包括第一个和最后一个值。

例子

start = 1, end = 100, n = 5   
Output: [1, 25, 50, 75, 100]

start = 1, end = 100, n = 4   
Output: [1, 33, 66, 100]

start = 1, end = 100, n = 2   
Output: [1, 100]

我目前拥有
的是 我实际上有一个可行的方法,但我一直觉得我在想这个并且错过了一些更简单的东西?这是最有效的方法还是可以改进?

def steps(start, end, n):
    n = min(end, max(n, 2) - 1)
    mult = end / float(n)
    yield start
    for scale in xrange(1, n+1):
        val = int(mult * scale)
        if val != start:
            yield val

请注意,我确保此函数将始终至少返回范围的下限值和上限值。所以,我强迫n >= 2

仅作为搜索参考,我使用它从渲染序列中采样图像帧,您通常需要第一个、中间、最后一个。但我希望能够更好地扩展以处理非常长的图像序列并获得更好的覆盖范围。

已解决:从所选答案

我最终使用了@vartec 答案的这个稍微修改过的版本,作为生成器,并且还限制了n安全值:

def steps(start,end,n):
    n = min(end, max(n, 2))
    step = (end-start)/float(n-1)
    return (int(round(start+x*step)) for x in xrange(n))
4

5 回答 5

5

您需要适当的舍入:

def steps(start,end,n):
    if n<2:
        raise Exception("behaviour not defined for n<2")
    step = (end-start)/float(n-1)
    return [int(round(start+x*step)) for x in range(n)]
于 2012-04-10T09:16:52.150 回答
4

额外的依赖,可能是矫枉过正,但简短,经过测试,应该给出正确的结果:numpy.linspace

>>> numpy.linspace(1, 100, 4).astype(int).tolist()
[1, 34, 67, 100]
于 2012-04-10T09:00:24.973 回答
3

使用的问题range是步长必须是整数,因此您会遇到舍入问题,例如steps(1,100,4) == [1, 33, 66, 100]. 如果您想要整数输出但想要尽可能多的一步,请使用浮点数作为您的步长。

>>> def steps(start,end,n):
...    step = (end-start)/float(n-1)
...    return [int(round(start+i*step)) for i in range(n)]

>>> steps(1,100,5)
>>> [1, 26, 51, 75, 100]
>>> steps(1,100,4)
>>> [1, 34, 67, 100]
>>> steps(1,100,2)
>>> [1, 100]
>>>
于 2012-04-10T08:46:45.647 回答
1
>>> from itertools import count
>>> def steps(start,end,n):
        yield start
        begin = start if start>1 else 0
        c = count(begin,(end-begin)/(n-1))
        next(c)
        for _ in range(n-2):
            yield next(c)
        yield end


>>> list(steps(1,100,2))
[1, 100]
>>> list(steps(1,100,5))
[1, 25, 50, 75, 100]
>>> list(steps(1,100,4))
[1, 33, 66, 100]
>>> list(steps(50,100,3))
[50, 75, 100]
>>> list(steps(10,100,10))
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

可以缩短为

>>> from itertools import islice, count
>>> def steps(start,end,n):
        yield start
        begin = start if start>1 else 0
        c = islice(count(begin,(end-begin)/(n-1)),1,None)
        for _ in range(n-2):
            yield next(c)
        yield end
于 2012-04-10T07:28:28.847 回答
0

使用range有什么问题?这是您如何使用它的方法

>>> def steps(start,end,n):
    return [start]+range(start-1,end,end/(n-1))[1:]+[end]

>>> steps(1,100,5)
[1, 25, 50, 75, 100]
>>> steps(1,100,2)
[1, 100]
>>> 
于 2012-04-10T07:12:16.477 回答