Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Python generate a random number that excludes a set of numbers, without using recursion?

People also ask

How can I generate a random number within a range but exclude some?

After generating the random number you've to put the "holes" back in the range. This can be achieved by incrementing the generated number as long as there are excluded numbers lower than or equal to the generated one. The lower exclude numbers are "holes" in the range before the generated number.

How does Python random generate random numbers?

For "secure" random numbers, Python doesn't actually generate them: it gets them from the operating system, which has a special driver that gathers entropy from various real-world sources, such as variations in timing between keystrokes and disk seeks.

How do you generate a list of random numbers without duplicates or repeats in Python?

To generate random numbers without repeating in Python, you can use the random module function choices(). choices() takes a list and the number of random numbers you want to generate.


Generate one random number and map it onto your desired ranges of numbers.

If you wanted to generate an integer between 1-4 or 7-10, excluding 5 and 6, you might:

  1. Generate a random integer in the range 1-8
  2. If the random number is greater than 4, add 2 to the result.

The mapping becomes:

Random number:    1  2  3  4  5  6  7  8
Result:           1  2  3  4  7  8  9 10

Doing it this way, you never need to "re-roll". The above example is for integers, but it can also be applied to floats.


Use random.choice(). In this example, a is your lower bound, the range between b and c is skipped and d is your upper bound.

import random
numbers = range(a,b) + range(c,d)
r = random.choice(numbers)

A possible solution would be to just shift the random numbers out of that range. E.g.

def NormalWORange(a, b, sigma):
    r = random.normalvariate(a,sigma)
    if r < a:
        return r-b
    else:
        return r+b

That would generate a normal distribution with a hole in the range (a-b,a+b).

Edit: If you want integers then you will need a little bit more work. If you want integers that are in the range [c,a-b] or [a+b,d] then the following should do the trick.

def RangeWORange(a, b, c, d):
    r = random.randrange(c,d-2*b) # 2*b because two intervals of length b to exclude
    if r >= a-b:
        return r+2*b
    else:
        return r

I may have misunderstood your problem, but you can implement this without recursion

def rand(exclude):
    r = None
    while r in exclude or r is None:
         r = random.randrange(1,10)
    return r

rand([1,3,9])

though, you're still looping over results until you find new ones.


The fastest solution would be this (with a and b defining the exclusion zone and c and d the set of good answers including the exclusion zone):

offset = b - a
maximum = d - offset
result = random.randrange(c, maximum)
if result >= a:
    result += offset