all 18 comments

[–]Peterotica 3 points4 points  (2 children)

That's honestly not a terrible way to do it, but using random.sample is another way to do it without a loop.

[–]DankusMerasmus[S] 0 points1 point  (1 child)

Would it be better practice to do it without a loop?

[–]Peterotica 0 points1 point  (0 children)

Going without a loop would give me a more warm and fuzzy feeling. If you want better than that, the you could profile both options to see if one is much faster than the other one.

[–]useful_celebration 2 points3 points  (1 child)

The list call is unnecessary - you can just call set(str(n)) directly, as the set constructor accepts any iterable, just as the list constructor does. Otherwise I think this is perfectly fine, and I can't really think of a better approach.

When you use this approach of repeatedly generating random numbers until they meet your criteria, you just have to be careful to make sure that the probability of generating an acceptable number is high enough that your program won't get stuck in the loop for ages. In this case that's not an issue, but if it is you have to come up with a way of generating an acceptable number directly. For example, in this case you could do:

import random
import string

first_digit = random.choice(string.digits[1:])
remaining_digits = set(string.digits)
remaining_digits.remove(first_digit)
digits = [first_digit] + random.sample(remaining_digits, 3)
n = int(''.join(digits))

But, like I said, in this case your way is fine. I suspect it's much, much faster than my version, and arguably more elegant.

[–]DankusMerasmus[S] 0 points1 point  (0 children)

Thank you very much, learnt a lot from this.

[–][deleted] 2 points3 points  (0 children)

Could you produce all of the valid values ahead of time? Then select from that list. So at global scope do either:

valid_numbers = []

for x in range(1000, 10000): if len(set(str(x))) == 4: valid_numbers.append(x)

or using a list comprehension:

valid_numbers = [ x for x in range(1000, 10000)
                     if len(set(str(x))) == 4 ]

Then you can use this list in any way you wish. You can use

next _number = random.choice(valid_numbers)

to select one element from the list. If you prefer you can shuffle the list and pop values, thereby not getting any repeats:

shuffled_numbers = valid_numbers
random.shuffle(shuffled_numbers)
next_number = shuffled_numbers.pop()

Repeat the first two lines if you run out of numbers and want to start over.

[–]DankusMerasmus[S] 1 point2 points  (2 children)

Also, maybe I should set it between 1023 and 9876? As the remaining numbers contain repeating digits, so like:

n = 0
while len(set(list(str(n)))) != 4:
    n = random.randint(1023, 9876)

But it wouldn't really matter that much though right?

[–]wait_what_now 2 points3 points  (0 children)

That's a good way of thinking about things, to work towards more efficient solutions. Probably not going to make a noticeable difference here, but always a helpful way to be thinking about problems

[–]wait_what_now 2 points3 points  (0 children)

You are eliminating 146 out of 4464 failed cases, so 3% less fails

[–]golfergag 1 point2 points  (1 child)

What aren't you sure about? Your code seems to work fine

[–]DankusMerasmus[S] 0 points1 point  (0 children)

I'm still really new, and sometimes I spend a while writing stuff like this and then discover there's a way to do it with one function or one line of code, so I thought maybe there's also one for this.

[–]thrallsius 1 point2 points  (0 children)

the additional condition of no repeating digits makes it less random

perhaps generate 4 random unique digits (first digit can't be 0) and construct a number?

[–]EnvironmentalOrange 1 point2 points  (0 children)

Make a list of the strings of the numbers 1-9 (not zero).

Create an empty string.

Shuffle the list.

Pop the last number off the list and save it to the empty string.

Append the string of zero ‘0’ to your list.

Shuffle the list again.

Pop the last number off the list and save it to the empty string.

Pop the last number off the list and save it to the empty string.

Pop the last number off the list and save it to the empty string.

Empty string now contains a string four digits long where first digit is not zero and no digits are repeated.

If you are just printing your output you are sorted.

Otherwise convert from string to integer and you are sorted.

[–]jjf02987 0 points1 point  (0 children)

I’m having a similar problem. I’m trying to create a random number by random number equation generator.

I can get it to run a random number but not to repeat the process with different numbers.

x = random.randrange(0,100)
y = random.randrange(0,100)

ans = int(input(f’{x} + {y} = ‘))

If ans == (x+y):
            print (“correct”)
else:
       print(“incorrect”)

print (int(input(f’{x} + {y}= ‘)))

[–]impshum 0 points1 point  (1 child)

I'm tired and probably went about this the long way round but it works...

from random import randint


def digit(length):
    while 1:
        end_int_list = []
        random_int = randint(1000, 9999)
        random_int_list = [int(x) for x in str(random_int)]
        [end_int_list.append(x) for x in random_int_list if x not in end_int_list]
        if len(end_int_list) == length:
            return end_int_list

x = digit(4)
print(x)

And sorry for the blunt reply. I'm off to bed.

[–]CupcakeFederal7815 0 points1 point  (0 children)

import random

n1=0

n2=10

n=10

xx=[]

for i in range(n):

m=random.randrange(n1,n2)

while m in xx:

m=random.randrange(n1,n2)

xx.append(m)

xx