根据布尔值列表过滤列表

时间:2013-09-06 20:12:30

标签: python list numpy

我有一个值列表,我需要根据布尔值列表中的值进行过滤:

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]即可。

7 个答案:

答案 0 :(得分:142)

您正在寻找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用作变量名,它是一个内置函数。

答案 1 :(得分:33)

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])

或者看看Alex Szatmary的答案,如果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

答案 2 :(得分:29)

像这样:

filtered_list = [i for (i, v) in zip(list_a, filter) if v]

使用zip是并行迭代多个序列的'pythonic'方法,无需任何索引。将itertools用于这样一个简单的案例有点矫枉过正......

在你的例子中你应该做的一件事就是将事物与True进行比较,这通常是没有必要的。您只需撰写if filter[idx]==True: ...

,而不是if filter[idx]: ...

答案 3 :(得分:14)

要使用numpy执行此操作,即,如果您有一个数组a,而不是list_a

a = np.array([1, 2, 4, 6])
my_filter = np.array([True, False, True, False], dtype=bool)
a[my_filter]
> array([1, 4])

答案 4 :(得分:1)

filtered_list = [list_a[i] for i in range(len(list_a)) if filter[i]]

答案 5 :(得分:0)

内置函数zip可用于简化操作。

filtered_list = [a for a, f in zip(list_a, filter) if f]

答案 6 :(得分:-3)

使用python 3,您可以使用list_a[filter]来获取True值。要获取False的值,请使用list_a[~filter]