Filter a list based on a Boolean selector
I believe in code expressivity and this tip is exactly about that. Lately, I got into a situation where I had two lists and I needed to filter one based on the values of the other.
For that case, it is probably best to use compress function from itertools module. Imagine a task like this.
Let's say you have a list of students
students = ["Mike", "Frank", "Paul", "Sarah", "David", "Robin", "Bob", "Antony"]
Next to it, you have a list of score from tests
scores = [90, 67, 78, 43, 45, 87, 66, 78 ]
You need to keep only the students that passed the test with a score higher than 60.
A quick solution that came to my mind first was using zip function.
passed = []
for i in zip(students, percent_scores):
if i[i] > 60:
passed.append(i[0])
More pythonic way, better to use it with list comprehension.
passed = [i[0] for i in zip(students, scores if i[1] > 60]
Althought this is not terrible, It is not very expressive. There might be a better way how to code it. Much more clear. Using itertools.compress()
from itertools import compress
above_60 = [x > 60 for x in scores]
passed = compress(students, above_60)
list(passed)
Why do I believe this is better? Because it tells me exactly what it does. I do not read and decipher a raw for loop or a list comprehension. This is very expressive and easy to catch.
The compress function work in a straightforward way it - it takes and iterable and a sequence of True/False, and it filters out the items corresponding to False. As zip function it returns iterator so we need to iterate over it to get the data.