Reputation: 1
I would like to generate 4 digits random number in Python but exclude all the numbers that have a "0" inside. For example, 9230, 2012 will not be accepted since there is a 0.
My code is:
def my_custom_random():
exclude=[0]
randInt = randint(1000, 9999)
return my_custom_random() if randInt in exclude else randInt
def Q3a():
RandomNumber = my_custom_random())
print(RandomNumber)
Q3a()
But this code is not working. Anyone can help me ? Thanks.
Upvotes: 0
Views: 641
Reputation: 1
I hope it will help you
import random
def my_custom_random():
exclude = 0
digits = [0,1,2,3,4,5,6,7,8,9]
randNumber = random.sample(digits,4) #List of integers Ex. [2,9,1,6]
while exclude in randNumber:
randNumber = random.sample(digits,4)
return map(str,randNumber) #map(str, x) -> transform [2,9,1,6] to ['2','9','1','6']
def Q3a():
randNumber = my_custom_random()
randNumber = "".join(randNumber) # ['2','9','1','6'] to '2916'
print(int(randNumber))
Q3a()
In digits you can omit the 0, so you can write less code. This way you will never have numbers with zero.
def my_custom_random():
digits = [1,2,3,4,5,6,7,8,9]
randNumber = random.sample(digits,4)
return map(str,randNumber)
Upvotes: 0
Reputation: 4733
Congratulations for not picking the easy but expensive solution, consisting in calling 4 times the random number generator for a number between 1 and 9 inclusive.
we can basically keep your recursive scheme, but delegate the hard work to another function, isBadNumber()
. Like this:
def my_custom_random():
randInt = random.randint(1111, 9999)
return my_custom_random() if isBadNumber(randInt) else randInt
To decide whether some number is acceptable or not, we need some auxiliary function that returns the list of digits:
# get at least k digits for a number in some arbitrary base:
def xdigits(k, base, n):
if (n < base):
res = (k-1)*[0] + [n]
else:
res = xdigits(k-1, base, n // base) + [n % base]
return res
Trying:
>>>
>>> q.xdigits(4,10,56)
[0, 0, 5, 6]
>>>
>>> q.xdigits(4,10,123456)
[1, 2, 3, 4, 5, 6]
>>>
>>> q.xdigits(4,10,7702)
[7, 7, 0, 2]
>>>
Thus we can write our isBadNumber()
function like this:
def isBadNumber(n):
if ((n < 1111) or (n > 9999)):
return True
ds = xdigits(4, 10, n)
if (min(ds) < 1):
return True # having a zero
return False # passed all tests OK.
Rejection costs CPU time, so it is always nice if we can do without it. For each of the 4 digits, there are 9 possibilities, 1 to 9 inclusive. Hence the overall number of solutions is 94, hence 6561. As programmers use to do, we can decide to number them from 0 to 6560 inclusive.
So we can pick one of them like this:
>>>
>>> import random
>>> import functools as fn
>>>
>>> random.randint(0,6560)
3952
>>>
If we express this number in base 9 (not 10), we get 4 digits between 0 and 8 inclusive. This is exactly what we need, provided we add 1 to every digit.
>>>
>>> q.xdigits(4,9,3952)
[5, 3, 7, 1]
>>>
We add 1 to every digit, giving [6, 4, 8, 2]. Hence, the 3952-th solution is number 6482.
Going from 3952 thru [5,3,7,1] to 6482 can be done using some simple Python data massaging:
>>>
>>> ds1 = list(map(lambda n: n+1, [5, 3, 7, 1]))
>>> ds1
[6, 4, 8, 2]
>>>
>>> fn.reduce(lambda acc, d: acc*10 + d, ds1)
6482
>>>
So overall the rejection-free code would be like this:
def my_custom_random():
randomRank = random.randint(0, 9**4 - 1)
ds0 = xdigits(4, 9, randomRank)
ds1 = list(map(lambda n: n+1, ds0))
num = functools.reduce(lambda acc, d: acc*10 + d, ds1)
return num
Upvotes: 1
Reputation: 15693
Basically, if you don't want zeros then don't pick zeros. Pick from [1..9] only, so you never pick a zero.
Here is some pseudocode; my Python is not good.
function noZeros()
digits <- [1,2,3,4,5,6,7,8,9] // Zero omitted.
result <- 0
repeat 4 times
result <- 10 * result;
thisDigit <- pick a random entry from digits array
result <- result + thisDigit
end repeat
return result
end function noZeros
I am sure you can write a better version in Python.
Upvotes: 0