15

I am just wondering how do I make python generate random numbers other than a particular number? For instance, I want it to generate any number from 1 to 5 except 3, so the output would be 1, 2, 4, 5 and 3 will not be counted in the list. What can I do to achieve that?

An example would be like this:
There are five computerized players (Player 0 to 4) in a game.
Player 1 randomly selects one other player (except itself) and Player 2 to 4 will do the same thing.

So the output will be something like:

Player 1, who do you want to play with?
Player 1 chooses Player 2
Fenophter
  • 27
  • 8
bugbytes
  • 315
  • 1
  • 5
  • 13
  • This sounds like a [X-Y Problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem); do include what problem you are trying to solve here, not how to achieve one detailed bit of a perceived solution. – Martijn Pieters Jul 28 '13 at 10:58

6 Answers6

22

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]
kaya3
  • 47,440
  • 4
  • 68
  • 97
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • 5
    Or `[x for x in xrange(1, 5) if x != 3]` – Maciej Gol Jul 28 '13 at 10:24
  • what if i want it to switch? say now i want 3 to be removed. and later i need other number like 1 or 2 to be removed. can i use the same def func or should i create a new one? – bugbytes Jul 28 '13 at 10:46
  • @user2626540: What are you trying to do? – Martijn Pieters Jul 28 '13 at 10:46
  • @user2626540 If you want something like that then simply use `r =range(1,5);r.remove(3)`, and then to remove 2 or some other number use remove again : `r.remove(1)` – Ashwini Chaudhary Jul 28 '13 at 10:49
  • hmm @MartijnPieters im trying to make a game whereby there are 5 players and when it is player 1 (computer) turns to play, player 1 can only choose 0- 4 players (other than itself) and i need to do that for all player 1-4... – bugbytes Jul 28 '13 at 10:54
  • @user2626540: See my solution; shuffle the numbers, then pick numbers from the list. Voila, random numbers without repetition. – Martijn Pieters Jul 28 '13 at 10:55
  • @user2626540 I've added another solution, may be that's what you wanted. – Ashwini Chaudhary Jul 28 '13 at 11:04
  • thank you for the help! i think I would be using the list.remove() or the return code you just wrote :) – bugbytes Jul 28 '13 at 11:08
  • 3
    For python3 you can't do `+` between ranges. It should be `r = list(range(1,n)) + list(range(n+1, end))` (source: [Python - Unsupported type(s) : range and range](https://stackoverflow.com/a/13318111/7053344)) – Thanasis1101 Aug 22 '19 at 16:25
6

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)

Nathan
  • 71
  • 1
  • 3
5

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).

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Hi I am not trying to generate random numbers. I already have the numbers which is 0-5 (player 0 - 5) and i need say, player 1 to choose another player (0-5) other than itself randomly. thank you so much! – bugbytes Jul 28 '13 at 11:02
2

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".)

torek
  • 448,244
  • 59
  • 642
  • 775
  • That's not uniform - consider an example for 5 players, when I am player 1 and I roll the dice, then player 2 has twice larger probability to be selected than other players – Jakub M. Jul 28 '13 at 11:31
  • @JakubM.: it was (and still is) not clear whether he wants any kind of fairness here. But no, player 2 doesn't have extra probability: we pick *one fewer* numbers, and move everyone up after "me". – torek Jul 28 '13 at 11:32
  • if he didn't, he would not use random numbers :) but yes, it should be said explicitly. Maybe OP does not know yet that he wants the selections to be fair – Jakub M. Jul 28 '13 at 11:34
  • Note that in Python 3.10, `random.choice` takes in a sequence so you should use `random.randint(0, 4)` instead of `random.choice(0, 4)`. The latter will throw an error: TypeError: Random.choice() takes 2 positional arguments but 3 were given – AlienKevin Aug 15 '22 at 11:42
  • @AlienKevin: good point - in fact this was changed way back in Python 2.7 or earlier! I'll update. – torek Aug 16 '22 at 05:55
0

The idea is. To pick random number from LIST(A) And each time it picks random number from LIST(A) the LIST(A) gets smaller. So you cant repeat. If Python pics '2' first time. It can't do it second time because '2' is not in LIST(A) ...

import random 
random_numbers =  [1,2,3,4,5] 
X = []
while True:
    one = random.choice(random_numbers))
    # print(one)
    if str(one) not in X:
        X.append(str(one))
        break

    if '2' in X:
        print("Last number was 2 with out repeating!")
        print("You did it u pick random numbers one by one with out repeating")
    random_numbers.remove(one)

print(X)
colidyre
  • 4,170
  • 12
  • 37
  • 53
wr3stl3r
  • 1
  • 1
0

I suggest use a recursion function.

import random

def randint_exc(start, end, exception):
    res = random.randint(start, end)
    if res != exception:
        return res
    else:
        return randint_exc(start, end, exception)

test = randint_exc(1, 4, 1)
print(test)
# results will be 2 or 3 or 4

For variable number of exception, you can use *args argument.

def randint_exc(start, end, *exception):
    res = random.randint(start, end)
    if res not in exception:
        return res
    else:
        return randint_exc(start, end, *exception)

test1 = randint_exc(1, 4, 1)
print(test1)
# results will be 2 or 3 or 4
test2 = randint_exc(1, 4, 1, 2)
print(test2)
# results will be 3 or 4

Or you can use list for more easy-reading.

def randint_exc(start, end, exception_list):
    res = random.randint(start, end)
    if res not in exception_list:
        return res
    else:
        return randint_exc(start, end, exception_list)

test1 = randint_exc(1, 4, [1])
print(test1)
# results will be 2 or 3 or 4
test2 = randint_exc(1, 4, [1, 2])
print(test2)
# results will be 3 or 4
j3rry
  • 145
  • 1
  • 1
  • 6