Alternative to zip() for Pavlovia

I wrote a long script in Python to prepare my stimuli for a study, and thought I was very clever, and now realized that at least one function—zip()—won’t work in Pavlovia. I wonder if there is a good alternative?

I will post my script as it currently exists below.

It basically takes pairs of names, shuffles them while maintaining the pairs, attaches a column of images of the appropriate gender (after these are shuffled), and a column indicating which side the names will appear on. Happy to provide more info if necessary, but I think the important question I have right now is just what to do with all of the lines of code using the zip() function.

thisExp=psychoJS.experiment;

win=psychoJS.window;
event=psychoJS.eventManager;
shuffle = util.shuffle;

Array.prototype.append = [].push;

#List of round names and spiky names
MaleNamesR = ["Abel", "Allen", "Lewis", "Linus"]
MaleNamesS = ["Eric", "Hector", "Chris", "Curtis"]

#zip them so you can shuffle while keeping pairs intact; then unzip then for later
MaleNames = list(zip(MaleNamesR, MaleNamesS))
random.shuffle(MaleNames)
MaleNamesR, MaleNamesS = zip(*MaleNames)
MaleNamesR = list(MaleNamesR)
MaleNamesS = list(MaleNamesS)

FemaleNamesR = ["Anne", "Joanna", "Noelle", "Norah"]
FemaleNamesS = ["Rita", "Erica", "Pippa", "Tessa"]

FemaleNames = list(zip(FemaleNamesR, FemaleNamesS))
random.shuffle(FemaleNames)
FemaleNamesR, FemaleNamesS = zip(*FemaleNames)
FemaleNamesR = list(FemaleNamesR)
FemaleNamesS = list(FemaleNamesS)

#Do the same thing as above but with sides of the screen
MaleSides1 = ["-.2", "-.2", ".2", ".2"]
MaleSides2 = [".2", ".2", "-.2", "-.2"] 

MaleSides = list(zip(MaleSides1, MaleSides2))
random.shuffle(MaleSides)
MaleSides1, MaleSides2 = zip(*MaleSides)
MaleSides1 = list(MaleSides1)
MaleSides2 = list(MaleSides2)

FemaleSides1 = ["-.2", "-.2", ".2", ".2"]
FemaleSides2 = [".2", ".2", "-.2", "-.2"] 

FemaleSides = list(zip(FemaleSides1, FemaleSides2))
random.shuffle(FemaleSides)
FemaleSides1, FemaleSides2 = zip(*FemaleSides)
FemaleSides1 = list(FemaleSides1)
FemaleSides2 = list(FemaleSides2)

#Prep images in the same way.
YMaleImages = ["072_y_m_n_b.jpg",
"013_y_m_n_b.jpg",
"016_y_m_n_a.jpg",
"025_y_m_n_a.jpg"] #list of young male images
OMaleImages = ["149_m_m_n_b.jpg",
"026_m_m_n_a.jpg",
"032_m_m_n_a.jpg",
"038_m_m_n_b.jpg"]
YFemaleImages = ["048_y_f_n_b.jpg",
"010_y_f_n_a.jpg",
"022_y_f_n_b.jpg",
"040_y_f_n_b.jpg"]
OFemaleImages = ["080_m_f_n_a.jpg",
"019_m_f_n_b.jpg",
"029_m_f_n_b.jpg",
"043_m_f_n_a.jpg"]

shuffle(YMaleImages)
shuffle(OMaleImages)
shuffle(YFemaleImages)
shuffle(OFemaleImages)

YMaleImages_A = YMaleImages[0:2] #take just the top half of the random young male images
YMaleImages_B = YMaleImages[2:4]

OMaleImages_A = OMaleImages[0:2]
OMaleImages_B = OMaleImages[2:4]

YFemaleImages_A = YFemaleImages[0:2]
YFemaleImages_B = YFemaleImages[2:4]

OFemaleImages_A = OFemaleImages[0:2]
OFemaleImages_B = OFemaleImages[2:4]

Males1 = YMaleImages_A + OMaleImages_A 
Males2 = YMaleImages_B + OMaleImages_B

c = list(zip(Males1, Males2))
random.shuffle(c)
Males1, Males2 = zip(*c)
Males1 = list(Males1)
Males2 = list(Males2)

Females1 = YMaleImages_A + OMaleImages_A 
Females2 = YMaleImages_B + OMaleImages_B

c = list(zip(Females1, Females2))
random.shuffle(c)
Females1, Females2 = zip(*c)
Females1 = list(Females1)
Females2 = list(Females2)

#Put different stimuli together into columns
NamesR = MaleNamesR + FemaleNamesR
NamesS = MaleNamesS + FemaleNamesS
Sides1 = MaleSides1 + FemaleSides1
Sides2 = MaleSides2 + FemaleSides2
Images1 = Males1 + Females1
Images2 = Males2 + Females2

#shuffle the columns 
AllTrials = list(zip(NamesR, NamesS, Sides1, Sides2, Images1, Images2))
random.shuffle(AllTrials)
NamesR, NamesS, Sides1, Sides2, Images1, Images2 = zip(*AllTrials)

NamesR = list(NamesR)
NamesS = list(NamesS)
Sides1 = list(Sides1)
Sides2 = list(Sides2)
Images1 = list(Images1)
Images2 = list(Images2)

AllTrials = [NamesR, NamesS, Sides1, Sides2, Images1, Images2]

Try putting the following code in a JS only code component in Begin Experiment

zip = function zip() {
    var args = [].slice.call(arguments);
    var shortest = args.length==0 ? [] : args.reduce(function(a,b){
        return a.length<b.length ? a : b
    });

    return shortest.map(function(_,i){
        return args.map(function(array){return array[i]})
    });
}

I got this from Javascript equivalent of Python's zip function - Stack Overflow

If the arrays are unequal length then this version should silently ignore the extra bits of the longer ones.

Thanks for the reply. However, I’m getting the following error.

Screen Shot 2022-06-14 at 12.07.35 PM

I’ve had a look at your code and the zip function was working fine.

The problem was matrix addition.

Instead of Males1 = YMaleImages_A + OMaleImages_A you need to use Males1 = YMaleImages_A.concat(OMaleImages_A)

The zip function was failing because the arguments were incorrect.

Also you were using AllTrials[trials.thisN,2] instead of AllTrials[2][trials.thisN] to address items in two dimensional arrays.

Thank you! It is now running smoothly!!

Though now I have to figure out why my images aren’t showing up… But this seems to be a separate problem because 1) if I just name a static image it also doesn’t show up, and 2) I’m not getting a resource not found error.

Edit: Nevermind, for some reason I’m now getting this error:

Screen Shot 2022-06-16 at 1.04.23 PM

I have this getting defined on the LoadJobs routine.