The way this method works is that each range represents a fraction of the sum total of all possible values in all the ranges. If n
is the total number of all possible values, you can imagine the values in the ranges being distributed as follows:
1------10|11-----14|15---------------40|41-----49|....|(n-x)-----n
range 1 | range 2 | range 3 | range 4 |....| range n
Where 1-10
corresponds to the values in range 1, and so on.
From there on it is the simple matter of generating a random number from 1
to n
, figuring out which range it belongs to and which value in that range it corresponds to.
Let the ranges be represented as an array of tuples, as
ranges = [(2, 50), (500, 600), (630, 890)]
Assuming that the ranges are sorted and do not overlap each other, first we have to find the total number of integers spanning these ranges, i.e. the total number of possible values we can generate (n
). We store the lengths of these ranges in an array lengths
. Pseudocode:
lengths = ranges.map(range => range.max - range.min + 1)
Note that the map function specified above holds good only for inclusive ranges. Depending on the types of your ranges, you may have to change it. Also note that n = sum(lengths)
.
Let x
be a random number in the range 1
to n
(inclusive). Then the array index i
of the range in which the x
th integer is found is given as:
i = 0
while (x > lengths[i]) {
x -= lengths[i]
i++
}
After this loop, x
will contain the index of the random number in range i
. That is, if x
is 3, the random number is the third number in range i
.
The required random number is then given by ranges[i].min + (x - 1)
.