John H
John H

Reputation: 87

random list choice: How do I make sure the same item isn't ever repeated twice in a row, one after the other?

import random

welcomes = ["Hello","Hi","What's up","YO", "Piss off"]

chosen = random.choice(welcomes)

print("You have entered the welcome cave ----- {} -----".format(chosen))

How do I make sure that Hello for example isn't repeated twice in a row? It's fine if they're repeated again later, just not straight after.

Upvotes: 1

Views: 2656

Answers (6)

Ms. Vella
Ms. Vella

Reputation: 1

Put [a = list.consumableList] instead of just the list in the = output

(replace the lowercase list in the brackets with the name of your list)

Upvotes: 0

Anton vBR
Anton vBR

Reputation: 18914

My take: We create two identical lists. In a loop we pop one value from one list and if the length of that list is smaller than the original list - 1 we reset the list to its original state:

import random

origin = ["Hello","Hi","What's up","YO", "Piss off"]
welcomes = origin.copy()

for i in range(5):
    if len(welcomes) < len(origin) - 1:
        welcomes = origin.copy()
    random.shuffle(welcomes) # shuffle
    chosen = welcomes.pop() # pop one value
    print("You have entered the welcome cave ----- {} -----".format(chosen))

E.g output with 5 loops:

You have entered the welcome cave ----- Piss off -----
You have entered the welcome cave ----- YO -----
You have entered the welcome cave ----- Piss off -----
You have entered the welcome cave ----- YO -----
You have entered the welcome cave ----- What's up -----

Upvotes: 0

damisan
damisan

Reputation: 1047

If you want to generate a very long stream of greetings having the property: no consecutive greetings are the same (Online demos: last version):

import random

def random_hello():
    welcomes = ["Hello", "Hi", "What's up", "YO", "Piss off"]
    last_hello = None
    while 1:
        random.shuffle(welcomes)
        if welcomes[0] == last_hello:
            continue
        for item in welcomes:
            yield item
        last_hello = welcomes[-1]


hellower = iter(random_hello())
for _ in range(1000):
    print(next(hellower))

Or when you worry about deterministic time, swap elements (with 1st):

if welcomes[0] == last_hello:
    welcomes[0], welcomes[1] = welcomes[1], welcomes[0]

or random:

if welcomes[0] == last_hello:
    swap_with = random.randrange(1, len(welcomes))
    welcomes[0], welcomes[swap_with] = welcomes[swap_with], welcomes[0]

Upvotes: 1

MSeifert
MSeifert

Reputation: 152860

You could do it with a hit&miss approach:

import random

class RandomChoiceNoImmediateRepeat(object):
    def __init__(self, lst):
        self.lst = lst
        self.last = None
    def choice(self):
        if self.last is None:
            self.last = random.choice(self.lst)
            return self.last
        else:
            nxt = random.choice(self.lst)
            # make a new choice as long as it's equal to the last.
            while nxt == self.last:   
                nxt = random.choice(self.lst)
            # Replace the last and return the choice
            self.last = nxt
            return nxt

One chould refine it with random.choices and weights (requires python-3.6) but that approach should work for all python versions:

>>> welcomes = ["Hello","Hi","What's up","YO", "Piss off"]
>>> gen = RandomChoiceNoImmediateRepeat(welcomes)
>>> gen.choice()
'YO'

Or if you don't like hit&miss you can also draw a random index between 0 and the length of the list - 2 and add 1 if it's equal or higher than the previous one. That ensures that no repeats can happen and only requires one call to random to get the next choice:

import random

class RandomChoiceNoImmediateRepeat(object):
    def __init__(self, lst):
        self.lst = lst
        self.lastidx = None

    def choice(self):
        if self.lastidx is None:
            nxtidx = random.randrange(0, len(self.lst))
        else:
            nxtidx = random.randrange(0, len(self.lst)-1)
            if nxtidx >= self.lastidx:
                nxtidx += 1
        self.lastidx = nxtidx
        return self.lst[nxtidx]

Upvotes: 0

Himanshu dua
Himanshu dua

Reputation: 2513

Use random.sample instead of random.choice. Find online demo

import random

welcomes = ["Hello","Hi","What's up","YO", "Piss off"]

chosen = random.sample(welcomes,2)

for item in chosen:
  print("You have entered the welcome cave ----- {} -----".format(item))

Upvotes: 2

Ofer Sadan
Ofer Sadan

Reputation: 11972

The use of random.sample like other answers suggested is only useful when you know you'll only need a certain number of items, like 2. The best way to ensure randomness and no repeats is to use random.shuffle:

import random
welcomes = ["Hello","Hi","What's up","YO", "Piss off"]
random.shuffle(welcomes)

Which well shuffle the list in-place, and then you can just start to pop items away from the list, until it's done:

while len(welcomes)>0:
    print("You have entered the welcome cave ----- {} -----".format(welcomes.pop())

That will work for a list of any length, and you can use this process until the entire list is done. You can also add another loop around the whole process if you want to keep it going forever and not just until the list is over.

Upvotes: 0

Related Questions