web-dev-qa-db-ja.com

ブール値のリストに基づいてリストをフィルタリングする

ブール値のリストの値を指定してフィルタリングする必要がある値のリストがあります。

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]

ラインは機能しますが、(私には)少しやり過ぎに見えます。同じことを達成するためのもっと簡単な方法があるのではないかと思っていました。


アドバイス

以下の回答にある2つの良いアドバイスの要約:

1-組み込み関数なので、リストにfilterという名前を付けないでください。

2-不要なため、if filter[idx]==True..のようにTrueと比較しないでください。 if filter[idx]を使用するだけで十分です。

104
Gabriel

あなたが探している 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を変数名として使用しないでください。これは組み込み関数です。

156

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
36
Hammer

そのようです:

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

Zipを使用することは、インデックス付けを必要とせずに、複数のシーケンスを並列に反復処理する「Pythonの」方法です。このような単純なケースにitertoolsを使用するのは少しやり過ぎです...

あなたの例であなたが本当にやるべきことの1つは、物事をTrueと比較することです。これは通常必要ありません。 if filter[idx]==True: ...の代わりに、単にif filter[idx]: ...と書くことができます。

31
Bas Swinckels

Numpyを使用してこれを行うには、つまり、list_aの代わりに配列aがある場合:

a = np.array([1, 2, 4, 6])
my_filter = np.array([True, False, True, False], dtype=bool)
a[my_filter]
> array([1, 4])
14
Alex Szatmary
filtered_list = [list_a[i] for i in range(len(list_a)) if filter[i]]
1
Daniel Braun