Random sample without repeating same item more than 3 times in a row

Hi all!

I’m creating lists of stimuli before my experiment in the coder. One master list I’m pulling from has 20 items, 10 of each stimulus. I need to randomly sample from that master list, but on the condition that each stimulus isn’t repeated more than 3 times in a row.

I hope someone can provide a solution or point me in the right direction!

Here’s an example of the text file I’m pulling from:
Screen Shot 2022-10-04 at 4.03.05 PM

Assuming that you are sampling without replacement and that you can generate the whole list in advance, you can do something like this to pre-generate the order. The idea is to shuffle the stimulus list, check if it meets your requirement of not having more than 3 consecutive items that are the same, and if it does you exit the loop :slight_smile:

master_list = ["maintain"]*10 + ["supress"] * 10

valid_sequence = False

while not valid_sequence:
    # Shuffle the list
    random.shuffle(master_list)
    
    # Validate the sequence
    valid_sequence = True
    for i in range(2, len(master_list)):
        if master_list[i] == master_list[i-1] and master_list[i] == master_list[i-2]:
            valid_sequence = False
            break
1 Like

That worked perfectly! Thank you.

Quick follow-up question going off of this: could this be adapted to meet the same requirement for another master list, where items start with the same path?

For example, I have another master list where there are unique images being pulled from two different folders:

As you can see, the beginning of the paths are the same for neg vs positive but each element is distinct. So could your code be used instead to satisfy the same requirement but with the beginning of the path?

if i.startswith("Stimuli/Faces/resized_neg_faces")
or
if i.startswith("Stimuli/Faces/resized_positive_faces")

You mean that there should not be three consecutive images from the same path (e.g., Stimuli/Faces/resized_neg_faces)?

One way to adapt it is to only look at the first 25 characters, as these allow you to distinguish between the positive and negative folders

# Validate the sequence
    valid_sequence = True
    for i in range(2, len(master_list)):
        if master_list[i][:25] == master_list[i-1][:25] and master_list[i][:25] == master_list[i-2][:25]:
            valid_sequence = False
            break

Your approach also works I think:

# Validate the sequence
    valid_sequence = True
    for i in range(2, len(master_list)):
        if master_list[i].startswith("Stimuli/Faces/resized_neg_faces") and master_list[i - 1].startswith("Stimuli/Faces/resized_neg_faces") and master_list[i - 2].startswith("Stimuli/Faces/resized_neg_faces"):
            valid_sequence = False
            break
        if master_list[i].startswith("Stimuli/Faces/resized_positive_faces") and master_list[i - 1].startswith("Stimuli/Faces/resized_positive_faces") and master_list[i - 2].startswith("Stimuli/Faces/resized_positive_faces"):
            valid_sequence = False
            break
1 Like

Thanks for all the help! That solution worked perfectly.