Фильтрация списка на основе списка логических значений
у меня есть список значений которые нужно отфильтровать значения в список булевых значений:
list_a = [1, 2, 4, 6]
filter = [True, False, True, False]
Я создаю новый отфильтрованный список со следующей строкой:
filtered_list = [i for indx,i in enumerate(list_a) if filter[indx] == True]
что приводит к:
print filtered_list
[1,4]
линия работает, но выглядит (для меня) немного излишне, и мне было интересно, есть ли более простой способ добиться того же.
советы
резюме двух хороших советов, приведенных в ответах ниже:
1-Не называйте список filter
как я сделал, потому что это встроенная функция.
2-Не сравнивайте вещи с True
как я if filter[idx]==True..
так как это не нужно. Просто используя if filter[idx]
достаточно.
5 ответов:
вы ищете
itertools.compress
:>>> from itertools import compress >>> list_a = [1, 2, 4, 6] >>> fil = [True, False, True, False] >>> list(compress(list_a, fil)) [1, 4]
сравнение времени (py3.x):
>>> list_a = [1, 2, 4, 6] >>> fil = [True, False, True, False] >>> %timeit list(compress(list_a, fil)) 100000 loops, best of 3: 2.58 us per loop >>> %timeit [i for (i, v) in zip(list_a, fil) if v] #winner 100000 loops, best of 3: 1.98 us per loop >>> list_a = [1, 2, 4, 6]*100 >>> fil = [True, False, True, False]*100 >>> %timeit list(compress(list_a, fil)) #winner 10000 loops, best of 3: 24.3 us per loop >>> %timeit [i for (i, v) in zip(list_a, fil) if v] 10000 loops, best of 3: 82 us per loop >>> list_a = [1, 2, 4, 6]*10000 >>> fil = [True, False, True, False]*10000 >>> %timeit list(compress(list_a, fil)) #winner 1000 loops, best of 3: 1.66 ms per loop >>> %timeit [i for (i, v) in zip(list_a, fil) if v] 100 loops, best of 3: 7.65 ms per loop
не используйте
filter
В имя переменной, это встроенная функция.
С numpy:
In [128]: list_a = np.array([1, 2, 4, 6]) In [129]: filter = np.array([True, False, True, False]) In [130]: list_a[filter] Out[130]: array([1, 4])
или см. ответ Алекса Сатмары, если list_a может быть массивом numpy, но не фильтровать
Numpy обычно дает вам большой прирост скорости, а также
In [133]: list_a = [1, 2, 4, 6]*10000 In [134]: fil = [True, False, True, False]*10000 In [135]: list_a_np = np.array(list_a) In [136]: fil_np = np.array(fil) In [139]: %timeit list(itertools.compress(list_a, fil)) 1000 loops, best of 3: 625 us per loop In [140]: %timeit list_a_np[fil_np] 10000 loops, best of 3: 173 us per loop
вот так:
filtered_list = [i for (i, v) in zip(list_a, filter) if v]
используя
zip
это "питонический" способ итерации по нескольким последовательностям параллельно, без необходимости какой-либо индексации. Использование itertools для такого простого случая немного перебор ...одна вещь, которую вы делаете в своем примере, вы действительно должны прекратить делать, это сравнивать вещи с истиной, обычно это не нужно. Вместо
if filter[idx]==True: ...
, вы можете просто написатьif filter[idx]: ...
.