简体   繁体   中英

Shuffle two lists in the same order in python

I have a question about shuffling, but first, here is my code:

from psychopy import visual, event, gui
import random, os
from random import shuffle
from PIL import Image
import glob
a = glob.glob("DDtest/targetimagelist1/*")
b = glob.glob("DDtest/distractorimagelist1/*")
target = a
distractor = b
pos1 = [-.05,-.05]
pos2 = [.05, .05]

shuffle(a)
shuffle(b)

def loop_function_bro():
    win = visual.Window(size=(1280, 800), fullscr=True, screen=0, monitor='testMonitor', color=[-1,-1,-1], colorSpace='rgb')
        distractorstim = visual.ImageStim(win=win,
        image= distractor[i], mask=None,
        ori=0, pos=pos1, size=[0.5,0.5],
        color=[1,1,1], colorSpace='rgb', opacity=1,
        flipHoriz=False, flipVert=False,
        texRes=128, interpolate=True, depth=-1.0)

    targetstim= visual.ImageStim(win=win,
        image= target[i], mask=None,
        ori=0, pos=pos2, size=[0.5,0.5],
        color=[1,1,1], colorSpace='rgb', opacity=1,
        flipHoriz=False, flipVert=False,
        texRes=128, interpolate=True, depth=-2.0)

    distractorstim.setAutoDraw(True)
    targetstim.setAutoDraw(True)
    win.flip()
    event.waitKeys(keyList = ['space'])

for i in range (2):  
    loop_function_bro()

This code randomly shuffles a bunch of images and displays them. However, I would like it is shuffle the images in the same order so that both lists are displayed in the same random order. Is there an way to do this?

Cheers, :)

The simplest way I can think to handle this is use a separate list for indices, and shuffle it instead.

indices = list(xrange(len(a)))  # Or just range(len(a)) in Python 2
shuffle(indices)

This question has been answered here and here . I particularly like the following for its syntactic simplicity

randomizedItems = map(items.__getitem__, indices)

For a complete working example, see code below. Note that I've changed quite a bit to make the code much shorter, cleaner and faster. See comments.

# Import stuff. This section was simplified.
from psychopy import visual, event, gui  # gui is not used in this script
import random, os, glob
from PIL import Image

pos1 = [-.05,-.05]
pos2 = [.05, .05]

# import two images sequences and randomize in the same order
target = glob.glob("DDtest/targetimagelist1/*")
distractor = glob.glob("DDtest/distractorimagelist1/*")
indices = random.sample(range(len(target)), len(target))  # because you're using python 2
target = map(target.__getitem__, indices)
distractor = map(distractor.__getitem__, indices)

# Create window and stimuli ONCE. Think of them as containers in which you can update the content on the fly.
win = visual.Window(size=(1280, 800), fullscr=True, screen=0, monitor='testMonitor', color=[-1,-1,-1])  # removed a default value
targetstim = visual.ImageStim(win=win, pos=pos2, size=[0.5,0.5])
targetstim.autoDraw = True
distractorstim = visual.ImageStim(win=win, pos=pos1, size=[0.5,0.5])  # removed all default values and initiated without an image. Set autodraw here since you didn't seem to change it during runtime. But feel free to do it where you please.
distractorstim.autoDraw = True

# No need to pack in a function. Just loop immediately. Rather than just showing two stimuli, I've set it to loop over all stimuli.
for i in range(len(target)):
    # set images. OBS: this may take some time. Probably between 20 and 500 ms depending mainly on image dimensions. Smaller is faster. It's still much faster than generating a full Window/ImageStim each loop though.
    distractorstim.image = distractor[i]
    targetstim.image = target[i]

    # Display and wait for answer
    win.flip()
    event.waitKeys(keyList = ['space'])

Another way to randomize the images while maintaining the pairing is something you'd probably do anyway sometime: put them together in a list of dictionaries, where each dict represents a trial. So rather than the two map lines, do:

trialList = [{'target':target[i], 'distractor':distractor[i]} for i in indices]

Try printing the trial list ( print trialList ) to see what it looks like. And then loop over trials:

for trial in trialList:
    # set images.
    targetstim.image = trial['target']
    distractorstim.image = trial['distractor']

    # Display and wait for answer. Let's record reaction times in the trial, just for fun.
    win.flip()
    response = event.waitKeys(keyList = ['space'], timeStamped=True)
    trial['rt'] = response[0][1]  # first answer, second element is rt.

I would create an array of numbers, shuffle it and sort the image lists both according to the shuffled numbers.

So both lists are shuffled in the same way.

    data1=[foo bar foo]
    data2=[bar foo bar]
    data3=[foo bar foo]
    alldata=zip((data1,data2,data3))
# now do your shuffling on the "outside" index of alldata then
    (data1shuff,data2shuff,data3shuff) = zip(*alldata)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM