Python random module: How can I generate a random number which includes certain digits?

Viewed 213

I am trying to generate a random number in Python, but I need it to include certain digits.

Let's say the range I want for it is between 100000 and 999999, so I want it to be in that range but also include digits like 1, 4, and 5.

Is there a way to do this?

3 Answers

you can build the number digit by digit

>>> import random
>>> def fun(required=(),size=6):
        result = list(required)
        n = size-len(result)
        result.extend( random.randint(0,10) for _ in range(n)) # fill in the remaining digits
        random.shuffle(result) 
        assert any(result) #make sure that there is at least one non zero digit
        while not result[0]: #make sure that the first digit is non zero so the resulting number be of the required size
            random.shuffle(result)
        return int("".join(map(str,result)))

>>> fun([1,4,5])
471505
>>> fun([1,4,5])
457310
>>> fun([1,4,5])
912457
>>> fun([1,4,5])
542961
>>> fun([1,4,5])
145079
>>> 

The obvious answer to me is brute force.

import random

def check(digits,number):
    passes = True
    number = str(number)
    for k in digits:
        if not str(k) in number:
            passes = False
            break
    return passes

def genRandom(digits):
    minimum = 100000
    maximum = 1000000
    r = minimum+int(random.random()*(maximum-minimum))
    while not check(digits,r):
        r = minimum + int(random.random() * (maximum - minimum))
    return r

print(genRandom([1,4,5]))

From reading comments I've seen 3 other solid suggestions. First randomly replace digits with the needed values. Which sounds simple but requires some ugliness to avoid replacing digits that you have designated as necessary and to avoid index errors when potentially getting digits past the end of your number.

import random

def genRandom(digits):
    digits = [str(k) for k in digits]
    minimum = 100000
    maximum = 1000000
    r = str(minimum+int(random.random()*(maximum-minimum)))
    for k in digits:
        while not k in r:
            i = int(random.random()*len(r))
            if r[i] in digits:
                if i==len(r)-1:
                    if not r[i] in r[0:i]:
                        continue
                elif not r[i] in r[0:i]+r[i+1:]:
                    continue
            if i==len(r)-1:
                r=r[0:i]+k
            else:
                r=r[0:i]+k+r[i+1:]
    return(r)

print(genRandom([1,4,5]))

The third option of generating a list of acceptable numbers and picking from that was well stated by enke in their answer. While this is a nice looking answer it is actually substantially more intensive in terms of runtime for a single call.

The best answer in my opinion is Copperfield's build the number digit by digit.

The easiest way I can think of doing this is by adding a few extra numbers to the beginning or end of your range and then mapping those extra numbers to the ones that you want. Using your example of 1, 4, and 5 this example shows how that would work.

import random

num = random.randint(99997, 999999)
if num == 99997:
  num = 1
elif num == 99998:
  num = 4
elif num == 99999:
  num = 5
print(num)
Related