The task is simple: given N, generate a random integer with no repeating digits.
'''
Generate a random number of length, N and all digits
are unique
'''
from __future__ import print_function
import random
from collections import OrderedDict
# keep generating till all are unique
# This is a brute force approach where I store the digits generated
# so far in a OrderedDict and if the next random number is already
# there, i ignore it.
def randN(n):
digits = OrderedDict()
while len(digits) < n:
d = random.randint(0, 9)
if d == 0 and not digits.keys():
continue
else:
if not digits.get(str(d), None):
digits[str(d)] = 1
return int(''.join(digits.keys()))
def _assert(randi, n):
assert len(str(randi)) == n
assert len(set(str(randi))) == n
for _ in range(100000):
_assert(randN(10), 10)
_assert(randN(1), 1)
_assert(randN(5), 5)
I have a feeling there is a better approach to solve this, which is why I am posting it here.
1 Answer 1
Not quite one line, but here's a much simpler solution:
import random
def randN(n):
assert n <= 10
l = list(range(10)) # compat py2 & py3
while l[0] == 0:
random.shuffle(l)
return int(''.join(str(d) for d in l[:n]))
Explanation:
The problem wants N unique digits. To get those, first make a list of all the digits, then shuffle them and cut off the unwanted digits (it should be noted that if you have many more than 10 digits, shuffling the whole lot would be expensive if you only want a handful).
To turn the list of digits into an integer, the shortest way is to stringify each digit and then join them into one string, and parse that back into an integer.
But wait! If the first digit is 0, the parsed string will be one digit shorter sometimes. So, earlier in the code, simply repeat the shuffle until some other digit comes first.
Since the initial order of the list has the 0 at the beginning, we don't need to do an extra shuffle before the loop.
-
3\$\begingroup\$ You can use random.sample and xrange to simplify things a bit \$\endgroup\$raptortech97– raptortech972014年11月14日 03:15:22 +00:00Commented Nov 14, 2014 at 3:15
-
1\$\begingroup\$ @raptortech97 Ugh, I should've thought of
sample
, but avoidingxrange
was a deliberate simplification for py2/py3 compat since the performance won't matter for a list that small. \$\endgroup\$o11c– o11c2014年11月14日 03:38:08 +00:00Commented Nov 14, 2014 at 3:38 -
1\$\begingroup\$ @raptortech97 thanks for the reference to random.sample(). \$\endgroup\$Amit– Amit2014年11月14日 06:33:29 +00:00Commented Nov 14, 2014 at 6:33
/(\d).*1円/
while leads to a very simple (though not efficient) solution. \$\endgroup\$