根据布尔值列表过滤列表

Gab*_*iel 108 python numpy list

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

list_a = [1, 2, 4, 6]
filter = [True, False, True, False]
Run Code Online (Sandbox Code Playgroud)

我使用以下行生成一个新的筛选列表:

filtered_list = [i for indx,i in enumerate(list_a) if filter[indx] == True]
Run Code Online (Sandbox Code Playgroud)

这导致:

print filtered_list
[1,4]
Run Code Online (Sandbox Code Playgroud)

线路工作,但看起来(对我来说)有点矫枉过正,我想知道是否有更简单的方法来达到同样的目的.


建议

以下答案中给出的两个好建议的摘要:

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

2-不要True像我一样比较事情,if filter[idx]==True..因为这是不必要的.只是使用if filter[idx]就足够了.

Ash*_*ary 156

您正在寻找itertools.compress:

>>> from itertools import compress
>>> list_a = [1, 2, 4, 6]
>>> fil = [True, False, True, False]
>>> list(compress(list_a, fil))
[1, 4]
Run Code Online (Sandbox Code Playgroud)

时序比较(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
Run Code Online (Sandbox Code Playgroud)

不要filter用作变量名,它是一个内置函数.


Ham*_*mer 36

随着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])
Run Code Online (Sandbox Code Playgroud)

或者看看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
Run Code Online (Sandbox Code Playgroud)

  • 好点,在可能的情况下,我更喜欢使用“NumPy”而不是“list”。但是,如果您无论如何都需要使用“list”,则必须(使用“NumPy”解决方案)从两个列表创建“np.array”,使用布尔索引,最后使用“tolist()”方法将数组转换回列表。准确地说,您应该将这些对象创建纳入时间比较中。然后,使用“itertools.compress”仍然是最快的解决方案。 (2认同)

Bas*_*els 34

像这样:

filtered_list = [i for (i, v) in zip(list_a, filter) if v]
Run Code Online (Sandbox Code Playgroud)

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

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


Ale*_*ary 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])
Run Code Online (Sandbox Code Playgroud)

  • 如果将my_filter转换为布尔数组,则可以使用直接布尔索引,而无需使用`where`. (3认同)

Dan*_*aun 7

filtered_list = [list_a[i] for i in range(len(list_a)) if filter[i]]
Run Code Online (Sandbox Code Playgroud)