As is often the case in Python, you don't actually have to muck about with indices at all to do this.
First, here is a simple solution using your existing data structure. Iterate over mix
, and append each item to the appropriate list, depending on whether it's in possibilities
or not. (This is the same idea presented in this answer to "How to split a list based on a condition?")
mix = [
[1, 'Blue'],
[2, 'Black'],
[3, 'Black'],
[4, 'Red'],
]
possibilities = [
[1, 'Black'], [1, 'Red'], [1, 'Blue'], [1, 'Yellow'],
[2, 'Green'], [2, 'Black'],
[3, 'Black'], [3, 'Pink'],
[4, 'White'], [4, 'Blue'], [4, 'Yellow'],
[5, 'Purple'], [5, 'Blue'],
]
correct_guesses = []
bad_guesses = []
for item in mix:
if item in possibilities:
correct_guesses.append(item)
else:
bad_guesses.append(item)
print(correct_guesses)
print(bad_guesses)
Output:
[[1, 'Blue'], [2, 'Black'], [3, 'Black']]
[[4, 'Red']]
However, this does a lot of unnecessary looping. Each time you check item in possibilities
, the code has to iterate over possibilities
(which is a list) to see whether or not item
is there.
As others have commented, the issue here is your data structure. Instead of a list, possibilities
could be a dictionary. Checking whether a dictionary has a given key, or accessing the value associated with a given key, is O(n); essentially it's "instant" instead of having to go look for it.
possibilities = {
1: ['Black', 'Red', 'Blue', 'Yellow'],
2: ['Green', 'Black'],
3: ['Black', 'Pink'],
4: ['White', 'Blue', 'Yellow'],
5: ['Purple', 'Blue']
}
Here each key is an integer, and each value is a list of the colors that number allows. Then your for
loop would look like this, checking if the color is one allowed for that number
for item in mix:
number, color = item
if color in possibilities[number]:
correct_guesses.append(item)
else:
bad_guesses.append(item)
Do you see the problem, though? We're still doing the same thing: using in
on a list. We could turn each of those lists into a set instead, which can much more efficiently check whether or not it contains something:
possibilities = {
1: {'Black', 'Red', 'Blue', 'Yellow'},
2: {'Green', 'Black'},
3: {'Black', 'Pink'},
4: {'White', 'Blue', 'Yellow'},
5: {'Purple', 'Blue'}
}
The for
loop would remain the same.
With all that in mind, here's a complete solution. I've also changed the two-item lists to tuples, which serves no functional difference in this case, but is more idiomatic.
mix = [
(1, 'Blue'),
(2, 'Black'),
(3, 'Black'),
(4, 'Red'),
]
possibilities = {
1: {'Black', 'Red', 'Blue', 'Yellow'},
2: {'Green', 'Black'},
3: {'Black', 'Pink'},
4: {'White', 'Blue', 'Yellow'},
5: {'Purple', 'Blue'}
}
correct_guesses = []
bad_guesses = []
for item in mix:
number, color = item
if color in possibilities[number]:
correct_guesses.append(item)
else:
bad_guesses.append(item)
print(correct_guesses)
print(bad_guesses)
Output:
[(1, 'Blue'), (2, 'Black'), (3, 'Black')]
[(4, 'Red')]
P.S. Ideally you'd change how you generate possibilities
in the first place, but if you're faced with a situation where you have the lists of lists, and want to convert it into the corresponding dictionary of sets, this would work:
possibilities_list = [
[1, 'Black'], [1, 'Red'], [1, 'Blue'], [1, 'Yellow'],
[2, 'Green'], [2, 'Black'],
[3, 'Black'], [3, 'Pink'],
[4, 'White'], [4, 'Blue'], [4, 'Yellow'],
[5, 'Purple'], [5, 'Blue'],
]
possibilities_dict = {}
for num, color in possibilities_list:
if num in possibilities_dict:
possibilities_dict[num].add(color)
else:
possibilities_dict[num] = {color}
Or using defaultdict to simplify the logic:
from collections import defaultdict
possibilities_dict = defaultdict(set)
for num, color in possibilities_list:
possibilities_dict[num].add(color)