psychopy.org | Reference | Downloads | Github

Comparing two lists (lists created through clicks)

WIN10
PsychoPy version: 2020.1.3
Standard Standalone? (yes)
What are you trying to achieve?:
I’m trying to write a code, where a participant-generated list (polygonsList) is being compared to a correct list (polygonNameList). Only if all the items in both lists are the same (and a ClickCount has counted to 42), can the experiment be continued (for this a continue button should become visible and clickable).
The original list consists of 42 polygon names. In the experiment the participants will mark all polygons with two different colors, thus generating too a lists which consists of 42 polygon names. Only when all polygons have been marked (added to the particpant generated list) should a continue button become visible.

What specifically went wrong when you tried that?:
I’m having trouble defining the code which tells psychopy to check if both lists have the same polygon names, irrelevant of the order of the names ( if str(polygonsList) is str(polygonNameList): )

I’m positive it has something to do with the way the for loop and the participant generated list (polygonsList) is structured.
My debugging attempts concluded that the participant generated list has a different order of names and, because of the mouse clicks (which can last longer than a frame), sometimes the names are added multiple times to the list. I tried to stop this with the code at the beginning of the for polygon in polygons loop and be letting psychopy sort the list before comparing them, but it is not working consistently…

Following is the code I have so far. Any help is much appreciated!! This is probably a beginners mistake, but I can’t seem to figure this out…

#Begin Routine:
polygons = [polygon1_37, polygon2_2, polygon3_33, polygon4_8, polygon5_38, polygon6_18, polygon7_21, polygon8_4, polygon9_14, polygon10_42, polygon11_31, polygon12_13, polygon13_27, polygon14_34, polygon15_7, polygon16_20, polygon17_15, polygon18_29, polygon19_32, polygon20_1, polygon21_22, polygon22_23, polygon23_36, polygon24_11, polygon25_12, polygon26_25, polygon27_40, polygon28_10, polygon29_6, polygon30_28, polygon31_19, polygon32_41, polygon33_24, polygon34_9, polygon35_35, polygon36_16, polygon37_5, polygon38_39, polygon39_3, polygon40_26, polygon41_17, polygon42_30]

for polygon in polygons:
    polygon.setFillColor(None) 
    polygon.setLineColor(None)

#Code snippets to create multiple new pieces(circles) to mark the polygons
pieces = [redPieceM, greenPieceM]
picked = []
newPiece = None
movingPiece = None

ClickCountNewPiece = 0
CountPolygons = False
polygonNameList = ['polygon1_37', 'polygon2_2', 'polygon3_33', 'polygon4_8', 'polygon5_38', 'polygon6_18', 'polygon7_21', 'polygon8_4', 'polygon9_14', 'polygon10_42', 'polygon11_31', 'polygon12_13', 'polygon13_27', 'polygon14_34', 'polygon15_7', 'polygon16_20', 'polygon17_15', 'polygon18_29', 'polygon19_32', 'polygon20_1', 'polygon21_22', 'polygon22_23', 'polygon23_36', 'polygon24_11', 'polygon25_12', 'polygon26_25', 'polygon27_40', 'polygon28_10', 'polygon29_6', 'polygon30_28', 'polygon31_19', 'polygon32_41', 'polygon33_24', 'polygon34_9', 'polygon35_35', 'polygon36_16', 'polygon37_5', 'polygon38_39', 'polygon39_3', 'polygon40_26', 'polygon41_17', 'polygon42_30']

polygonsList = [] #empty list for storing polygons names     
multipleAnswered = False

#ContinueButton for online Experiment, turned off at beginning
ContinueButton = visual.ShapeStim(win, fillColor= 'red', fillColorSpace= 'rgb', vertices=((-0.06, -0.05), (-0.06, 0.05), (0.06, 0.05), (0.06, -0.05)), closeShape=True, pos=(.70, -.40), name='ContinueButton')
ContinueButtonText = visual.TextStim(win, text='Weiter', height = 0.03, pos=(.70, -.40))

ContinueButton.setAutoDraw(False)
ContinueButtonText.setAutoDraw(False)
ContinueButtonOn = False
ContinueButtonSelected = False

-----------------------------------------------------------
#Each frame:

for polygon in polygons:
    if polygon.contains(mouseMulti):
        #store the first response:
        if len(polygonsList) == 0:
            polygonsList.append(polygon.name)
        #for following responses, only store if they aren't a repetition of the immediate prior one (entry [-1]):
        elif polygonsList[-1] != polygon.name:
            polygonsList.append(polygon.name)
                
    if len(polygonsList): #and CountPolygons:  #if there is something in the list and 42 pieces have been counted via ClickCountNewPiece
        #print(str(polygonNameList))
        polygonsList.sort()
        #print(str(polygonsList))
        
        #check if there is anything inside the list
    if str(polygonsList) is str(polygonNameList):  #if both lists are equal (same names)
        print('comparison polygonslists')
        multipleAnswered = True
        continueRoutine = False
   
#draw and enable button once multipleAnswered is complete
        if multipleAnswered and not ContinueButtonOn:
            ContinueButton.setAutoDraw(True)
            ContinueButtonText.setAutoDraw(True)
            ContinueButtonOn = True
    
        #check for click in button when it is on:
        if ContinueButtonOn and mouseMulti.isPressedIn(ContinueButton) and not ContinueButtonSelected:
            ContinueButtonSelected = True
        
    #if activated button is pressed, store data and proceed
            if ContinueButtonSelected:
                thisExp.addData(piece.name, polygon.name)
            #store data of all piece.names in polygons
            # polygon.name, piece.name, redPieceMValue, greenPieceMValue
            #possible need to add: trialHandler.addData('component name', clicked data with values)
                continueRoutine = False

I remember running into this a lot when I first started learning Python after spending years programming in Matlab - comparing lists is certainly not this language’s strongpoint.

There are elegant ways of doing list comparison and plenty of packages (such as numpy) which make list comparisons more Matlab-like (i.e. processing them as matrices), but if you’re new to the language I recommend using for loops to go through the list. It’s messy, but more straightforward to get your head around!

allMatch = True
for item in polygonsList:
    if item not in polygonNameList:
        allMatch = False

if allMatch:
    

You could clean it up a little by using list comprehension:

if any([True for item in polygonsList if item in polygonNameList]):

but there’s no shame in sticking with more long-form notation, it’s more important to be clear than to be brief!

1 Like

Thank you for your answer!

The code provided is definitely an improvement!!! Now the Continue Button shows up at least (I never managed that) but it is not clickable yet. Could be because of how I structured the code afterwards, but I haven’t figured that out yet.

And another small problem: The ContinueButton shows up after only one item has been added to the former empty list (polygonList). But I want it to only show up, wenn all elements of the polygonNameList are inside the polygonList. Is there a way to make that happen too? I could add a clickcount, but that doesn’t really solve the problem the way I want it too… Could set() be of any use?

I didn’t have much time today to look more into it sadly…

For anyone following this thread in the future - I figured out what went wrong. I simply had to change the two list names (they are kind of confusing because their names are so similar). And the ContinueButton had some wrong indentations…

...
if len(polygonsList):
    allMatch = True
    for item in polygonNameList:
        if item not in polygonsList:
            allMatch = False
    if allMatch:
        multipleAnswered = True
...

Thank you very much @TParsons!! Your answer was super helpful :slight_smile:

1 Like