How to conditionally remove a dictionary from a list

If this template helps then use it. If not then just delete and start from scratch.

OS (e.g. Win10):
PsychoPy version 2020.2.4:
**What are you trying to achieve?:
I am programming an experiment that produces series of numbers that either update randomly or update based on a rule (a mathematical operation). I have the list of rules programmed containing a bunch of dictionaries:

conditionContainer = [
{'difficulty': 'easy', 'steps': [1]},
{'difficulty': 'easy', 'steps': [2]},
{'difficulty': 'easy', 'steps': [3]},
{'difficulty': 'easy', 'steps': [4]},
{'difficulty': 'easy', 'steps': [-1]},
{'difficulty': 'easy', 'steps': [-2]},
{'difficulty': 'easy', 'steps': [-3]},
{'difficulty': 'easy', 'steps': [-4]},
{'difficulty': 'hard', 'steps': [1, 2]},
{'difficulty': 'hard', 'steps': [2, 3]},
{'difficulty': 'hard', 'steps': [-2, -1]},
{'difficulty': 'hard', 'steps': [-3, -2]},
{'difficulty': 'hard', 'steps': [-2, 1]},
{'difficulty': 'hard', 'steps': [-2, -3]},
{'difficulty': 'hard', 'steps': [2, -1]},
{'difficulty': 'hard', 'steps': [-2, 3]}]

The program alternates between rule and non-rule phases. When in a non-rule phase, the program randomly draws upon a rule and then updates the number on-screen based on one of the steps in the rule. In a rule-phase, the program picks one of those rules and then consistently applies it over a set number of trials until a certain number of trials is reached. Currently, the experiment works, but I am trying to modify it so that when a rule is selected, IF it is a rule phase, then that rule is dropped from the list so it will not be chosen again once it becomes time to select a new rule. Here is the function that determines the rule (it is located in the begin experiment tab of the first screen):

def determineCurrentRule(phaseParameters, currentTarget, conditionContainer, targetBounds):
## takes as input phase information, the current target, all conditions, and target boundaries
## randomly iterates through the rules until it finds one that stays in bounds

## make a list of condition indices
availableIndices = list(range(len(conditionContainer)))

out = 1

while out:
    
    try:
        ## randomly sample from conditions
        ## the line below is the one that will fail if all conditions are exhausted
        chosenIndex = availableIndices[random.randint(0, len(availableIndices))]
        ## update the current rule
        currentRule = conditionContainer[chosenIndex]
        ## if a condition is successfully drawn, drop it from the available indices list
        availableIndices.remove(chosenIndex)
        out = 0
        
    except:
        ## if all conditions are exhausted
        ## regenerate the target stimulus to be close to the median of possible targets
        currentTarget = random.randint(currentTarget - 2, currentTarget + 2)
        ## refresh available indicies so all rules can be sampled again
        availableIndices = list(range(len(conditionContainer)))
return([currentRule, currentTarget])

What did you try to make it work?:

Within the “try” segment of the above function, I tried adding this:

        if phaseParameters['phaseId'] == 'rulePhase':
           availableIndices.remove(chosenIndex)

Within the “except” segment of the above function, I commented out this:

   ## refresh available indicies so all rules can be sampled again
   availableIndices = list(range(len(conditionContainer)))

What specifically went wrong when you tried that?:

The experiment still runs, but it is not removing the rules from the availableIndices after a rule has been successfully drawn.

Rather than choosing an index and then deleting it, you could use .pop(), which will “pop” an index from a list into a variable. e.g.

currentRule = conditionContainer.pop(chosenIndex)

I would also recommend replacing the try statement with an if statement with the conditions upon which you expect it to work, e.g. if len(availableIndices) > 0, as this means you can still have access to error messages when it goes wrong