How do you create a random list of integers, but exclude a certain number?

Viewed 1103

I'd like to create a random list of numbers in python, but exclude a certain number, k.

I can create a random list of integers: l = [random.randint(0,10) for i in range(5)] Then I can remove the number, k, if it's there, and add another random number in the range, but this seems like too many steps.

In researching this, It's quite easy to find out how to create a random number from a range and exclude a certain number, for example: print (choice([i for i in range(0,9) if i not in [2,5,7]])) I could do this the amount of times I need to create the array -- but this seems more complex than necessary.

Would appreciate some feedback this

5 Answers

Make a list of the numbers in the range, and remove k from the list. Then you can use random.choices() to select multiple elements from the list.

numbers = list(range(0, 11))
numbers.remove(k)
result = random.choices(numbers, k=5)

You could write a generator that yields random numbers of your choosing, and take the first n:

def random_numbers_except(a, b, exclusions):
    while True:
        while (choice := random.randint(a, b)) in exclusions:
            pass
        yield choice

numbers = [number for _, number in zip(range(5), random_numbers_except(0, 10, [2, 5, 7]))

You can also create your generator and use that in your list comprehension.

def my_random_generator(n_values, min_value, max_value, excluded_values=None):
    if excluded_values is None:
        excluded_values = []

    count = 0

    while count < n_values:
        value = random.randint(min_value, max_value)
        while value in excluded_values:
            value = random.randint(min_value, max_value)
        yield value
        count += 1


# Then
l = [_ for _ in my_random_generator(5, 0, 10, [2, 5, 7])]

# Or, (added after the discussion below)
l = list(my_random_generator(5, 0, 10, [2, 5, 7]))

You can generate the random numbers to the range you need and subtract the amount of numbers you want to exclude. Whenever an exceptional number is chosen, you can map it to the end of the range.

Does that make sense? If not, maybe the code does:

import random

random_range = range(0,1000)
exclude = [5, 55, 555]

def generate(n:int, ran: range, exclude:list):
    exclusive_range = range(ran.start, ran.stop-len(exclude))
    randoms = []
    for i in range(n):
        r = random.choice(exclusive_range)
        if r in exclude:
            r = exclusive_range.stop + exclude.index(r)
        randoms.append(r)
    return randoms

x = generate(1000, random_range, exclude)

In my example, 5 will be mapped to 997, 55 will be panned to 998 and 555 will be mapped to 999.

You can choose random numbers from a range that is one shorter, and then for each individual selection add 1 to it when it is greater or equal to k:

import random

k = 50  # number to exclude
n = 100  # range: choices should be in {0,...,49,51,...,99}
rnd = random.randrange(0, n - 1)  # in {0,...,98}
rnd += int(rnd >= k)
Related