This works almost fine but the number starts with 0 sometimes:
import random
numbers = random.sample(range(10), 4)
print(\'\'.join(map(str, numbers)))
We generate the first digit in the 1 - 9 range, then take the next 3 from the remaining digits:
import random
# We create a set of digits: {0, 1, .... 9}
digits = set(range(10))
# We generate a random integer, 1 <= first <= 9
first = random.randint(1, 9)
# We remove it from our set, then take a sample of
# 3 distinct elements from the remaining values
last_3 = random.sample(digits - {first}, 3)
print(str(first) + ''.join(map(str, last_3)))
The generated numbers are equiprobable, and we get a valid number in one step.
rejection sampling method. Create a 4 digit random combination from 10 digits and resample if it doesn't match the criteria.
r4=0
while r4 < 1000:
r4=int(''.join(map(str,random.sample(range(10),4))))
noticed that this is essentially the same as @Austin Haskings's answer
This will allow zeros after the first digit -
numbers = random.sample(range(1,10),1) + random.sample(range(10),3)
[Fixed] Shift all four digits on one position is not right. Swap leading zero with fixed position is not right too. But random swap of the leading zero with any of nine positions is correct and gives equal probability:
""" Solution: randomly shuffle all numbers. If 0 is on the 0th position,
randomly swap it with any of nine positions in the list.
Proof
Lets count probability for 0 to be in position 7. It is equal to probability 1/10
after shuffle, plus probability to be randomly swapped in the 7th position if
0 come to be on the 0th position: (1/10 * 1/9). In total: (1/10 + 1/10 * 1/9).
Lets count probability for 3 to be in position 7. It is equal to probability 1/10
after shuffle, minus probability to be randomly swapped in the 0th position (1/9)
if 0 come to be on the 0th position (1/10) and if 3 come to be on the 7th position
when 0 is on the 0th position (1/9). In total: (1/10 - 1/9 * 1/10 * 1/9).
Total probability of all numbers [0-9] in position 7 is:
9 * (1/10 - 1/9 * 1/10 * 1/9) + (1/10 + 1/10 * 1/9) = 1
Continue to prove in the same way that total probability is equal to
1 for all other positions.
End of proof. """
import random
l = [0,1,2,3,4,5,6,7,8,9]
random.shuffle(l)
if l[0] == 0:
pos = random.choice(range(1, len(l)))
l[0], l[pos] = l[pos], l[0]
print(''.join(map(str, l[0:4])))
next
A Pythonic way to write would be to use 2 nested generators and next
:
from random import randint
from itertools import count
print(next(i for i in (randint(1023, 9876) for _ in count()) if len(set(str(i))) == 4))
# 8756
It's basically a one-liner variant of @MSeifert's answer
If you need many random numbers, you could invest some time and memory for preprocessing all the acceptable numbers:
import random
possible_numbers = [i for i in range(1023, 9877) if len(set(str(i))) == 4]
1023
and 9877
are used as boundaries because no int lower than 1023 or greater than 9876 can have 4 unique, distince numbers.
Then, you'd just need random.choice for a very fast generation:
print(random.choice(possible_numbers))
# 7234
I do not know Python well, but something like
digits=[1,2,3,4,5,6,7,8,9] <- no zero
random.shuffle(digits)
first=digits[0] <- first digit, obviously will not be zero
digits[0]=0 <- used digit can not occur again, zero can
random.shuffle(digits)
lastthree=digits[0:3] <- last three digits, no repeats, can contain zero, thanks @Dubu
A more useful iteration, actually creating a number:
digits=[1,2,3,4,5,6,7,8,9] # no zero
random.shuffle(digits)
val=digits[0] # value so far, not zero for sure
digits[0]=0 # used digit can not occur again, zero becomes a valid pick
random.shuffle(digits)
for i in range(0,3):
val=val*10+digits[i] # update value with further digits
print(val)
After stealing pieces from other solutions, plus applying the tip from @DavidHammen:
val=random.randint(1,9)
digits=[1,2,3,4,5,6,7,8,9]
digits[val-1]=0
for i in random.sample(digits,3):
val=val*10+i
print(val)