Choosing random integers except for a particular number for python?

It sounds as if you want to produce a random set of numbers, then pick from those one-by-one. A random sequence without repetition, in other words.

Generate all those numbers, shuffle, then use .pop() to pick one at a time and remove it from the set of possibilities:

import random

numbers = range(5)  # list(range(5)) in Python 3
random.shuffle(numbers)

a_random_number = numbers.pop()
another_random_number = numbers.pop()

list.pop() removes the last value from the list of randomly shuffled numbers.

It may be enough even to just shuffle and then loop over the list:

players = range(5)
random.shuffle(players)

for player in players:
    # random ordering of players

You can bundle the random-number-sequence production up as an iterator in a function:

import random

def random_number_sequence(n):
    numbers = range(n)  # list(range(n)) in Python 3
    random.shuffle(numbers)
    return iter(numbers)

random_sequence = random_number_sequence(5)
a_random_number = next(numbers)
another_random_number = next(numbers)

You can call next() on the iterator and it'll produce another random number from the sequence, until the sequence is exhausted (at which point StopIteration is returned).


In this case, random.choice will work fine, but there's also an obvious simple mathematical transform you could use. If players are numbered 0 through 5 inclusive, and you are player X, then:

number = random.randint(0, 4) # first, pick a number: 0, 1, 2, 3, or 4
if number >= X:               # then, if it's me or higher...
    number += 1               # move forward one player

Note that this works no matter which player number you are. If you are #5, this picks a number between 0 and 4, which is not you (because you are #5). If you are #0, this picks a number between 0 and 4, which is >= you (because you are #0) so you add 1 giving a number between 1 and 5. If you are #3, this picks a number between 0 and 4, and if it's 3 or 4 you bump it up one to 4 or 5 respectively.

Edit to add: this won't allow you to do "fair" alternation (where everyone gets a turn before someone gets to go again). If you want that, generating a list, using random.shuffle to put it in random order, and then picking from the list (with .pop() or similar) until it is empty is the way to go. You can then refill and re-shuffle the list for a new (but different) "fair" order.

(Note that this kind of thing is why it is important to figure out what you want before going about "how to get there".)


While other answers are correct. The use of intermediate lists is inefficient.


Alternate Solution: Another way you could do this is by choosing randomly from a range of numbers that is n-1 in size. Then adding +1 to any results that are greater than or equal to >= the number you want to skip.

The following function random_choice_except implements the same API as np.random.choice, and so adjusting size allows efficient generation of multiple random values:


import numpy as np

def random_choice_except(a: int, excluding: int, size=None, replace=True):
    # generate random values in the range [0, a-1)
    choices = np.random.choice(a-1, size, replace=replace)
    # shift values to avoid the excluded number
    return choices + (choices >= excluding)

random_choice_except(3, 1)
# >>> 0  <or>  2  
random_choice_except(3, 1, size=10)
# >>> eg. [0 2 0 0 0 2 2 0 0 2]

The behaviour of np.random.choice changes depending on if an integer, list or array is passed as an argument. To prevent unwanted behavior we may want to add the following assertion at the top of the function: assert isinstance(a, int)


Use random.choice on a list, but first remove that particular number from the list:

>>> import random
>>> n = 3
>>> end  = 5
>>> r = list(range(1,n)) + list(range(n+1, end))
>>> r
[1, 2, 4]
>>> random.choice(r)
2
>>> random.choice(r)
4

Or define a function:

def func(n, end, start = 1):
    return list(range(start, n)) + list(range(n+1, end))
... 
>>> r = func(3, 5)
>>> r
[1, 2, 4]
>>> random.choice(r)
2

Update:

This returns all numbers other than a particular number from the list:

>>> r = range(5)
for player in r:
    others = list(range(0, player)) + list(range(player+1, 5))
    print player,'-->', others
...     
0 --> [1, 2, 3, 4]
1 --> [0, 2, 3, 4]
2 --> [0, 1, 3, 4]
3 --> [0, 1, 2, 4]
4 --> [0, 1, 2, 3]

Tags:

Python

Random