173

我有一个值列表,我需要过滤给定布尔值列表中的值:

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]就足够了。

4

6 回答 6

236

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

于 2013-09-06T20:13:44.650 回答
56

像这样:

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

UsingzipPython式的方式,可以并行迭代多个序列,而不需要任何索引。这假设两个序列具有相同的长度(在最短的用完后拉链停止)。itertools用于这样一个简单的案例有点矫枉过正......

您在示例中真正应该停止做的一件事是将事物与 True 进行比较,这通常是没有必要的。而不是if filter[idx]==True: ...,你可以简单地写if filter[idx]: ...

于 2013-09-06T20:13:32.700 回答
44

使用 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 数组但不能过滤,请查看 Alex Szatmary 的回答

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
于 2013-09-06T21:08:03.600 回答
21

使用 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])
于 2013-09-06T21:05:59.753 回答
3
filtered_list = [list_a[i] for i in range(len(list_a)) if filter[i]]
于 2018-08-22T16:05:13.527 回答
-3

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

于 2020-05-04T09:16:55.223 回答