问题
How do I generate a random number from a specific set of digits? For example,
I want to generate numbers from the range 1-100,000
such that every number has only odd digits (for example: 111
, 1351
, 19711
etc..)
Using the random module I tried:
import random
rand = random.randint([1, 3, 5, 7, 9])
Is there any efficient way of doing it?
Thank you.
回答1:
Here is a solution using list-comprehension:
>>> random.sample([i for i in range(1,100_001) if all([int(x)%2==1 for x in str(i)])], 4)
[3115, 75359, 53159, 31771]
As pointed out in the comments below, the above code becomes more and more inefficient the larger the numbers get, due to all numbers being checked if each of them includes only odd-numbers. That includes numbers that are even.
IF we add another filter to first remove all even-numbers we reduce the amounts of comparisons that are being made by about a third.
Here is a quick comparison between the two:
import datetime
import random
def timer(var):
def wrapper(*args, **kwargs):
start = datetime.datetime.now()
result = var()
print(f"Elapsed time: {datetime.datetime.now()-start}")
return result
return wrapper
@timer
def allNumbers():
return random.sample([i for i in range(1, 1_000_001) if all([int(x) % 2 == 1 for x in str(i)])], 4)
@timer
def oddNumbers():
return random.sample([i for i in [x for x in range(1, 1_000_001) if x % 2 == 1] if all([int(x) % 2 == 1 for x in str(i)])], 4)
print("Calling allNumbers:")
print(allNumbers())
print("Calling oddNumbers:")
print(oddNumbers())
Output:
Calling allNumbers:
Elapsed time: 0:00:05.119071
[153539, 771197, 199379, 751557]
Calling oddNumbers:
Elapsed time: 0:00:02.978188
[951919, 1399, 199515, 791393]
回答2:
One way could be to define a list of odds from which to sample, but keeping in mind the how likely it should be for a number to be sampled randomly. Since there are ten times as many 2 digit numbers than 1 digit numbers, we need to set the weights of these sampling sizes according to this logic.
Following this reasoning, we could use numpy.random.choice
, which allows for sampling from a list following a probability distribution:
from numpy.random import choice
odds = ['1','3','5','7','9']
n_digits = 5 # up to 99999 for ex
range_digits = list(range(1,n_digits))
weights = [5**i for i in range_digits]
weights_sum = sum(weights)
probs = [i/weights_sum for i in weights]
sizes = choice(range_digits,size=n,p=probs)
[int(''.join(choice(odds,size))) for size in sizes]
# [3151, 3333, 1117, 7577, 1955, 1793, 5713, 1595, 5195, 935]
Let's check the generated distribution for 10_000
samples:
from collections import Counter
sizes = choice(range_digits,size=10_000,p=probs)
out = [int(''.join(choice(odds,size))) for size in sizes]
Counter(len(str(i)) for i in out)
# Counter({4: 8099, 3: 1534, 2: 304, 1: 63})
回答3:
Given the range you want is 1 - 100,000 you will never pick 100,000 because it has even digits: 0. Effectively your maximum allowed output is 99,999. That is five digits.
Your output might have invisible leading zeros: 975 is allowed, which is effectively 00975. Those leading zeros have to be allowed for in your code.
Pick how many leading zeros you have. 10% of the numbers in your range have a leading zero. 10% of those have a second leading zero. 10% of those (1 in 1,000) have a third leading zero and so on. Five leading zeros is 0 output. That is outside the allowed range, so you will need to start picking again. That will only happen very rarely.
Once you know how many leading zeros there are, you know how many other digits you need. Pick that many digits from the allowed digit list: [1, 3, 5, 7, 9].
回答4:
import random
print(random.randrange(1, 100000, 2))
来源:https://stackoverflow.com/questions/62931500/generate-random-numbers-only-with-specific-digits