파이썬에서는 단 하나의 진실 된 값 (즉, bool(value) is True
)을 가져야하는 목록이 있습니다 . 이것을 확인하는 영리한 방법이 있습니까? 지금은 목록을 반복하고 수동으로 확인하고 있습니다.
def only1(l)
true_found = False
for v in l:
if v and not true_found:
true_found=True
elif v and true_found:
return False #"Too Many Trues"
return true_found
이것은 우아하지 않고 비단뱀처럼 보입니다. 이를 수행하는 더 현명한 방법이 있습니까?
답변
가장 장황한 해결책이 항상 가장 비범 한 해결책은 아닙니다. 따라서 약간의 수정을 추가합니다 (일부 중복 된 부울 평가를 저장하기 위해).
def only1(l):
true_found = False
for v in l:
if v:
# a True was found!
if true_found:
# found too many True's
return False
else:
# found the first True
true_found = True
# found zero or one True value
return true_found
비교를위한 몇 가지 타이밍은 다음과 같습니다.
# file: test.py
from itertools import ifilter, islice
def OP(l):
true_found = False
for v in l:
if v and not true_found:
true_found=True
elif v and true_found:
return False #"Too Many Trues"
return true_found
def DavidRobinson(l):
return l.count(True) == 1
def FJ(l):
return len(list(islice(ifilter(None, l), 2))) == 1
def JonClements(iterable):
i = iter(iterable)
return any(i) and not any(i)
def moooeeeep(l):
true_found = False
for v in l:
if v:
if true_found:
# found too many True's
return False
else:
# found the first True
true_found = True
# found zero or one True value
return true_found
내 출력 :
$ python -mtimeit -s 'import test; l=[True]*100000' 'test.OP(l)'
1000000 loops, best of 3: 0.523 usec per loop
$ python -mtimeit -s 'import test; l=[True]*100000' 'test.DavidRobinson(l)'
1000 loops, best of 3: 516 usec per loop
$ python -mtimeit -s 'import test; l=[True]*100000' 'test.FJ(l)'
100000 loops, best of 3: 2.31 usec per loop
$ python -mtimeit -s 'import test; l=[True]*100000' 'test.JonClements(l)'
1000000 loops, best of 3: 0.446 usec per loop
$ python -mtimeit -s 'import test; l=[True]*100000' 'test.moooeeeep(l)'
1000000 loops, best of 3: 0.449 usec per loop
보시다시피 OP 솔루션은 여기에 게시 된 대부분의 다른 솔루션보다 훨씬 낫습니다. 예상대로 가장 좋은 것은 단락 동작이있는 사용자, 특히 Jon Clements가 게시 한 솔루션입니다. 적어도 True
긴 목록 에 두 개의 초기 값이있는 경우 .
True
값 이 전혀없는 경우에도 동일 합니다.
$ python -mtimeit -s 'import test; l=[False]*100000' 'test.OP(l)'
100 loops, best of 3: 4.26 msec per loop
$ python -mtimeit -s 'import test; l=[False]*100000' 'test.DavidRobinson(l)'
100 loops, best of 3: 2.09 msec per loop
$ python -mtimeit -s 'import test; l=[False]*100000' 'test.FJ(l)'
1000 loops, best of 3: 725 usec per loop
$ python -mtimeit -s 'import test; l=[False]*100000' 'test.JonClements(l)'
1000 loops, best of 3: 617 usec per loop
$ python -mtimeit -s 'import test; l=[False]*100000' 'test.moooeeeep(l)'
100 loops, best of 3: 1.85 msec per loop
나는 통계적 유의성을 확인하지 않았지만 흥미롭게도 이번에는 FJ가 제안한 접근 방식, 특히 Jon Clements가 제안한 접근 방식이 다시 분명히 우수 해 보입니다.
답변
수입이 필요하지 않은 것 :
def single_true(iterable):
i = iter(iterable)
return any(i) and not any(i)
또는 더 읽기 쉬운 버전 :
def single_true(iterable):
iterator = iter(iterable)
# consume from "i" until first true or it's exhausted
has_true = any(iterator)
# carry on consuming until another true value / exhausted
has_another_true = any(iterator)
# True if exactly one true found
return has_true and not has_another_true
이:
i
진정한 가치가 있는지 확인 합니다.- 다른 실제 값이 없는지 확인하기 위해 반복 가능한 지점에서 계속 찾습니다.
답변
단순히 True
값을 찾고 있는지 아니면 True
논리적으로 평가되는 다른 값 ( 11
또는 등 "hello"
)을 찾고 있는지에 따라 다릅니다 . 전자의 경우 :
def only1(l):
return l.count(True) == 1
후자의 경우 :
def only1(l):
return sum(bool(e) for e in l) == 1
새 목록을 만들지 않고도 단일 반복으로 계산과 변환을 모두 수행 할 수 있기 때문입니다.
답변
단락 동작을 유지하는 한 줄 답변 :
from itertools import ifilter, islice
def only1(l):
return len(list(islice(ifilter(None, l), 2))) == 1
상대적으로 초기에 두 개 이상의 실제 값을 갖는 매우 큰 이터 러블의 경우 여기에있는 다른 대안보다 훨씬 빠릅니다.
ifilter(None, itr)
(단 truthy 요소를 얻을 것이라는 반복자를 제공 x
하는 경우 truthy입니다 bool(x)
반환 True
). islice(itr, 2)
의 처음 두 요소 만 산출하는 iterable을 제공합니다 itr
. 이것을리스트로 변환하고 길이가 1인지 확인함으로써 우리는 두 개를 찾은 후 추가 요소를 확인할 필요없이 정확히 하나의 진실 요소가 존재하는지 확인할 수 있습니다.
다음은 몇 가지 타이밍 비교입니다.
-
설정 코드 :
In [1]: from itertools import islice, ifilter In [2]: def fj(l): return len(list(islice(ifilter(None, l), 2))) == 1 In [3]: def david(l): return sum(bool(e) for e in l) == 1
-
단락 동작 표시 :
In [4]: l = range(1000000) In [5]: %timeit fj(l) 1000000 loops, best of 3: 1.77 us per loop In [6]: %timeit david(l) 1 loops, best of 3: 194 ms per loop
-
단락이 발생하지 않는 큰 목록 :
In [7]: l = [0] * 1000000 In [8]: %timeit fj(l) 100 loops, best of 3: 10.2 ms per loop In [9]: %timeit david(l) 1 loops, best of 3: 189 ms per loop
-
작은 목록 :
In [10]: l = [0] In [11]: %timeit fj(l) 1000000 loops, best of 3: 1.77 us per loop In [12]: %timeit david(l) 1000000 loops, best of 3: 990 ns per loop
따라서 sum()
매우 작은 목록의 경우 접근 방식이 더 빠르지 만 입력 목록이 커지면 단락이 불가능할 때도 내 버전이 더 빠릅니다. 큰 입력에서 단락이 가능하면 성능 차이가 분명합니다.
답변
나는 네크로맨서 배지를 받고 싶었 기 때문에 Jon Clements의 탁월한 답변을 일반화하여 단락 논리의 이점을 보존하고 모든 사람에게 빠른 술어 검사를 수행했습니다.
따라서 여기에 있습니다 :
N (참) = n
def n_trues(iterable, n=1):
i = iter(iterable)
return all(any(i) for j in range(n)) and not any(i)
N (참) <= n :
def up_to_n_trues(iterable, n=1):
i = iter(iterable)
all(any(i) for j in range(n))
return not any(i)
N (참)> = n :
def at_least_n_trues(iterable, n=1):
i = iter(iterable)
return all(any(i) for j in range(n))
m <= N (참) <= n
def m_to_n_trues(iterable, m=1, n=1):
i = iter(iterable)
assert m <= n
return at_least_n_trues(i, m) and up_to_n_trues(i, n - m)
답변
>>> l = [0, 0, 1, 0, 0]
>>> has_one_true = len([ d for d in l if d ]) == 1
>>> has_one_true
True
답변
넌 할 수있어:
x = [bool(i) for i in x]
return x.count(True) == 1
또는
x = map(bool, x)
return x.count(True) == 1
@JoranBeasley의 방법을 기반으로 구축 :
sum(map(bool, x)) == 1