Specific instance of Problem
I have an int range from 1-100. I want to generate n total numbers within this range that are as evenly distributed
You need proper rounding:
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)]
Extra dependency and maybe overkill, but short, tested and should give correct results: numpy.linspace
>>> numpy.linspace(1, 100, 4).astype(int).tolist()
[1, 34, 67, 100]
>>> 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]
Can be shortened to
>>> 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
The problem with using range
is that the step must be an integer and so you get rounding issues, such as steps(1,100,4) == [1, 33, 66, 100]
. If you want integer outputs but want as even a step as possible, use a float as your step.
>>> 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]
>>>
What's wrong with using range? Here is how you can use it
>>> 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]
>>>