0

I have a list of numbers l = [0,1,2,3,4,5,6,7,8,9] from which I want to choose random numbers, without ever repeating the last chosen one.

So, if I generate a sequence of random numbers, the same should never be chosen twice in a row.

I select a random number from this list using the random.choice() method. If I get 4 the first time, it can't be chosen again on the second iteration, but will be available again on the third one.

How can I do that? Is there any package available in Python that provides random numbers this way?

Murtaza
  • 413
  • 1
  • 3
  • 13
  • 1
    does this answer your question? [Non-repetitive random number in numpy](https://stackoverflow.com/questions/8505651/non-repetitive-random-number-in-numpy) , if not please create a [complete and reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) – anky Mar 29 '20 at 08:07
  • 1
    No, because it provides a list of unique random integers whereas I need unique random int in every iteration. – Murtaza Mar 29 '20 at 08:13
  • 1
    why not generate the random numbers before you enter the loop? if not you can just use `np.shuffle` and take the first 2 values. – albusSimba Mar 29 '20 at 08:15
  • Just randomly shuffle the list of numbers. Then you can pull them off one-at-a-time from the shuffled list. – Tom Karzes Mar 29 '20 at 08:15
  • You will not find a library for this as it is very specific and I doubt someone would implement that already. But, you could easily create your own function! even publish it for others to use... – Tomerikoo Mar 29 '20 at 08:17

6 Answers6

1

You could create a generator to generate them:

import random

def random_without_pairs(data):
    values = set(data)
    previous = None
    while True:
        new = random.sample(values, 1)[0]
        yield new
        values.remove(new)
        if previous is not None:
            values.add(previous)
        previous = new

Note the use of random.sample(values, 1) to generate a list of one value from the set, as random.choice can only be used on sequences.

You can use it like this:

l = [0,1,2,3]
r = random_without_pairs(l)  # create the generator that will generate values from l
for i in range(10):
    print(next(r))

2
3
2
3
1
3
0
2
0
3

If you want to create a list of n random values without pairs from your list, you can use this little helper function:

def n_random_without_pairs(data, n):
    r = random_without_pairs(data)
    return [next(r) for _ in range(n)]

print(n_random_without_pairs(l, 10))

#[1, 3, 2, 3, 2, 3, 0, 1, 3, 1]
Thierry Lathuille
  • 23,663
  • 10
  • 44
  • 50
0

if you shuffle the list:

import random

a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
random.shuffle(a)
print(a)

result:

[7, 9, 0, 5, 1, 2, 4, 8, 6, 3]

Furthermore, if you do not want to modify the original list, you can create an index list and shuffle that:

index = list(range(len(a)))
random.shuffle(index)

for i in index:
    print(a[i])
daveg
  • 535
  • 2
  • 10
  • It works, but shuffling the whole list in order to extract only one value is very inefficient. – Thierry Lathuille Mar 29 '20 at 08:39
  • True, and now that the question is clarified, the only reasonable solution is to make a comparison to the previously drawn sample - I recommend your answer here :) – daveg Mar 29 '20 at 09:27
0

Okay I got the solution thanks to @albusSimba and @Tom Karzes

import random 

l = [0,1,2,3]
prev = [0]
for i in range(20):
    random.shuffle(l)
    if prev[i]==l[0]:
        a = l[1]
    else:
        a =l[0]
    prev.append(a)
    print(a)  
Murtaza
  • 413
  • 1
  • 3
  • 13
0

You can use a while loop to keep drawing from the pool until it is different from the previous pick:

import random

def draw(l):
    previous = object()
    while True:
        pick = random.choice(l)
        if pick != previous:
            previous = pick
            yield pick

so that the following code will always succeed:

previous = object()
picks = draw(l)
for i in range(10000):
    pick = next(picks)
    assert pick != previous
    previous = pick
blhsing
  • 91,368
  • 6
  • 71
  • 106
0

you can use the value that was chosen last to mask the array you are choosing from.

import numpy as np

# array to choose from 
a = np.arange(10)

#outputs
picks = []

# initialise first value
temp=None

for d in range(50):

    # choose from the value of array without the one chosen in the last iteration.
    temp = np.random.choice(a[a!=temp])

    picks.append(a[temp])
warped
  • 8,947
  • 3
  • 22
  • 49
0

random.shuffle() would have been best way to go, but since you want to include all items except the last you can start with the following.

l = [0,1,2,3,4,5,6,7,8,9]
ans = random.choice(l)
print(ans)
for i in range(10): # if you need infinite loop you can change this to while true:
    l2 = [x for x in l if x!=ans]
    ans = random.choice(l2)
    print(ans)
Yonas Kassa
  • 3,362
  • 1
  • 18
  • 27