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


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.