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.