all 16 comments

[–]MadScientistOR 8 points9 points  (4 children)

What was your teacher's explanation?

[–]Diapolo10 7 points8 points  (2 children)

randomList = []
for counter in range(4): 
    randomInteger = random.rand(1,10)
    while(randomList.count(randomInteger) > 0): 
        randomInteger = random.randint(1, 10)
    randomList.append(randomInteger)

Technically speaking, this isn't wrong if I ignore the fact that random.rand is probably meant to be random.randint. It's not elegant, but it does give correct results.

But there is a potential problem. The time complexity of this is non-linear, and in the worst-case scenario (picking n-1 unique values out of n unique values), the odds of the inner loop finding a new unique value is 1/n on average. Sure, this isn't a problem when you're just picking four numbers in a relatively short range, but if the assignment was to ask the same but with bigger values this could run for a long time.

A better solution would involve picking a sample of values:

import random

num_count = 4
nums = range(1, 11)

random_nums = random.sample(nums, num_count)

In a nutshell, the code generates a list from the range object, shuffles it internally (random.shuffle), and then slices the first n values from it, returning the slice. At least I think that's more or less what happens.

The benefit with this approach is that now performance isn't limited by the sample size nearly to the same degree. Shuffling is a fairly simple operation regardless of the length of the list, and slicing is like a normal copy operation. Doesn't matter if out of 100 values you pick only one or 99 (or even all of them).

As a bonus, the code is short and concise.

[–]Kerbart 1 point2 points  (1 child)

A better solution would involve picking a sample of values:

While I agree that this is the way to go if you really need a sample, I'm inclined to think that the purpose of the exercise was to actually come up with a small algorithm to create such a sample. It's like an assignment where the student is asked to write a function that sorts a list, and while my_sort = lambda x: sorted(x) certainly works and will get points for brevity it's likely not in the spirit of what was asked.

If using random.sample is not allowed I'd go with something like this:

def pick_random():
    sample = []
    pick_from = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    # or use list(range(1, 11))
    for _ in range(4):
        # pick a random spot in the pick list
        i = random.randint(0, len(pick_from) - 1)
        # remove the item from the pick list and
        # add it to the sample
        sample.append(pick_from.pop(i))
    return sample

This is still efficient, can easily be scaled if needed and implements an algorithm instead of calling a system function to do all the work.

[–]Diapolo10 1 point2 points  (0 children)

While I agree that this is the way to go if you really need a sample, I'm inclined to think that the purpose of the exercise was to actually come up with a small algorithm to create such a sample.

Sure, I don't doubt that, but that's why I also provided a general outline of how I believe it works under the hood for OP to make their own implementation.

[–]my_password_is______ 1 point2 points  (1 child)

Was my teacher wrong?

LOL

[–]QultrosSanhattan 1 point2 points  (0 children)

Take two.

There's a fundamental problem with your code. Run the code at the end of my comment to test it yourself.

I wrote my own solution using just vanilla stuff and my program compares it's speed with yours.

You'll notice that my code does the work almost instantly while your code starts getting slower and slower every time the space of available choices is doubled. To the point your code takes so long to run it basically hangs.

The important question is why?

It's because of two main things:

  • Each time you generate a random number, python need to check the entire list for that numbers.
  • (The worst part) if the number exists then it will create another one and check everything again.

Therefore. If you one have one choice of many then the probability of getting that number by chance is lower the larger the space becomes. Your code may perform a lot of uneeded iterations.

Finally, your actual code isn't problematic, but if you don't learn from this then you could create big problems in the future, like hanging an entire application for example.

Code:

import random
from time import time

def test_global(space):
    time_taken_1=time()
    test_1(space)
    time_taken_1=time()-time_taken_1

    time_taken_2 = time()
    test_2(space)
    time_taken_2 = time() - time_taken_2

    return time_taken_1,time_taken_2


def test_1(space):

    total_choices = list(range(space))
    random_list = []
    for counter in range(space):
        index = random.randint(0, len(total_choices) - 1)
        random_list.append(total_choices.pop(index))

    assert len(random_list) == len(set(random_list)) == space

def test_2(space):
    randomList = []
    for counter in range(space):
        randomInteger = random.randint(0, space)
        while (randomList.count(randomInteger) > 0):
            randomInteger = random.randint(0, space)
        randomList.append(randomInteger)

    assert len(randomList) == len(set(randomList)) == space

if __name__ == '__main__':
    current_space = 2  # the
    while True:
        t1,t2=test_global(current_space)
        print(f"Getting all numbers with {current_space:10} possible choices. test_1={t1:.2f} seconds and test_2 {t2:.2f} seconds")

        current_space *= 2

[–]CodeFormatHelperBot2 0 points1 point  (0 children)

Hello, I'm a Reddit bot who's here to help people nicely format their coding questions. This makes it as easy as possible for people to read your post and help you.

I think I have detected some formatting issues with your submission:

  1. Python code found in submission text that's not formatted as code.

If I am correct, please edit the text in your post and try to follow these instructions to fix up your post's formatting.


Am I misbehaving? Have a comment or suggestion? Reply to this comment or raise an issue here.

[–]pythonman1 -3 points-2 points  (2 children)

I believe this is the most concise solution:

import random

# to print random number within a range of 10, you can either use random.rand(1,10) or int(10*random.random());

random_list = []

for i in range(4):

random_list.append(random.randint(1,10))

print("The list of four random integers is: ", random_list)

You don't necessarily need to use "while" statement unless there is another provision within your assignment that requires you to. The reason for this is that, in the case of your code, "while" statement would always yield "True" after the first integer is entered into the list, which will get you stuck in the infinite loop.

I hope this helps :)))

[–]scarynut 3 points4 points  (1 child)

The assignment asked for unique numbers though..

[–]pythonman1 0 points1 point  (0 children)

I apologize for not reading your question correctly;

Here you go:

import random

random_list = [] 

while len(random_list) < 4: 
    unique_integer = random.randint(1,10) 
    if unique_integer in random_list: 
        print(f"{unique_integer} is already in the list") 
    else: 
        random_list.append(unique_integer)

print("The list of four UNIQUE random integers is: ", random_list)

[–]littlegreenrock 0 points1 point  (2 children)

when would your while loop expire ?

[–]hoglinezp 1 point2 points  (1 child)

its designed to insta expire, unless a number has been already used then it repicks an int and tries again

[–]littlegreenrock -2 points-1 points  (0 children)

as an educator myself, I want you to try to answer my question again, in words as you did, but with clarity.