根据布尔值列表筛选列表

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

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]

这句话很有效,但(对我来说)有点过分,我想知道是否有一种更简单的方法来实现同样的效果。


建议

以下答复中提出的两条良好建议摘要:

不要像我一样命名一个列表 filter,因为它是一个内置函数。

不要把东西和 True比较,就像我用 if filter[idx]==True..做的那样,因为它是不必要的。只用 if filter[idx]就够了。

152774 次浏览

像这样:

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

使用 zip蟒蛇并行迭代多个序列的方法,不需要任何索引。这假设两个序列具有相同的长度(在最短的运行结束后,zip 停止)。在这样一个简单的情况下使用 itertools有点过分了..。

在你的例子中,有一件事你真的应该停止做,那就是把事情和真相进行比较,这通常是没有必要的。您可以简单地编写 if filter[idx]: ...代替 if filter[idx]==True: ...

你要找的是 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 完成此操作,例如,如果使用数组 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])

麻木:

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 数组,但不能是过滤器,请查看 Alex Szatary 的答案

麻木通常也会给你一个很大的速度提升

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 = [list_a[i] for i in range(len(list_a)) if filter[i]]

对于 python3,您可以使用 list_a[filter]来获得 True