'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.
Solution 1:[1]
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))
Solution 2:[2]
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]
Solution 3:[3]
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.
Solution 4:[4]
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]
Solution 5:[5]
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 -----
Solution 6:[6]
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)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | Ofer Sadan |
| Solution 4 | |
| Solution 5 | |
| Solution 6 | Bender the Greatest |
