부울 목록을 기반으로 목록 필터링


127

부울 목록의 값을 필터링해야하는 값 목록이 있습니다.

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]만으로 충분합니다.


3
참고로, 이것은 스트림 압축 이라고하는 일반적인 병렬 컴퓨팅 기본 요소 입니다. (이 많은 병렬 알고리즘을위한 빌딩 블록으로 사용 되었기 때문에 그것이 간단하지 때문에 '프리미티브'이라하지만습니다)
BlueRaja - 대니 Pflughoeft

2
어떤 스타일의 노트 : if filter[indx] == True마십시오 하지 사용 ==당신이 신분을 확인하려는 경우 True사용 is. 어쨌든이 경우 전체 비교는 쓸모가 없으므로 간단히 사용할 수 있습니다 if filter[indx]. 마지막으로 내장 이름을 변수 / 모듈 이름 으로 사용 하지 마십시오 (이름을 참조하고 있습니다 filter). 같은 것을 사용하여 included(가) 그래서, if잘 읽고 ( if included[indx]).
Bakuriu

답변:


184

당신은 찾고 있습니다 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변수 이름으로 사용하지 마십시오 . 내장 함수입니다.


@Mehdi 나는 Matlab 방식이 매우 직관적이지 않다고 생각하지만 익숙한 것에 달려 있다고 생각합니다.
이안 Goldby

어떻게 선택할 수 [2, 6]있습니까?
Florent

알 겠어요, list(compress(list_a, [not i for i in fill]))돌아와야합니다[2, 6]
Florent

42

이렇게 :

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

using zip은 인덱싱 할 필요없이 여러 시퀀스를 병렬로 반복 하는 파이썬적인 방법입니다. 이것은 두 시퀀스의 길이가 같다고 가정합니다 (가장 짧은 시간이 지나면 zip이 중지됨). 사용 itertools같은 간단한 경우에하는 것은 약간의 과잉이다 ...

당신의 예제에서 당신이 정말로 멈춰야 할 한 가지는 True와 비교하는 것입니다. 이것은 일반적으로 필요하지 않습니다. 대신 if filter[idx]==True: ...간단히 if filter[idx]: ....


40

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

좋은 점 은 가능한 한 NumPyover 사용하는 것을 선호 list합니다. 그러나 list어쨌든 사용해야 하는 경우 ( NumPy솔루션 사용 ) np.array두 목록에서 생성하고 부울 인덱싱을 사용하고 마지막으로 메소드를 사용하여 배열을 다시 목록으로 변환 tolist()합니다. 정확히 말하면 이러한 객체 생성을 시간 비교에 포함해야합니다. 그런 다음 사용하는 itertools.compress것이 여전히 가장 빠른 솔루션입니다.
Nerxis

17

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

3
my_filter를 부울 배열로 바꾸면 where.
Bas Swinckels 2013 년


-1

파이썬 3을 사용 list_a[filter]하면 True값 을 얻을 수 있습니다. False값 을 얻으려면list_a[~filter]

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.