1. ホーム
  2. python

[解決済み] リストがたった一つの真理値を持っていることを確認するにはどうすればよいですか?

2023-03-29 08:40:39

質問

Pythonで、私は以下のようなリストを持っています。 1つだけ 真実の値(つまり 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

これはエレガントではなく、非常にpythonicではないようです。これを行うためのより巧妙な方法はありますか?

どのように解決するのですか?

最も冗長な解決策は、常に最もエレガントでない解決策というわけではありません。したがって、私は(いくつかの冗長なブーリアン評価を保存するために)わずかな修正を追加します。

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 によって投稿されたソリューションがそうです。少なくとも、2 つの初期 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

統計的な有意性は確認しませんでしたが、興味深いことに、今回も F.J. が提案したアプローチ、特に Jon Clements によるアプローチが明らかに優れているように見えます。