4

数字のリスト(または反復可能)がすべて同じ符号を持っているかどうかをどのように判断できますか?

これが私の最初の(ナイーブな)ドラフトです:

def all_same_sign(list):

    negative_count = 0

    for x in list:
        if x < 0:
            negative_count += 1

    return negative_count == 0 or negative_count == len(list)

これを行うためのよりPythonicおよび/または正しい方法はありますか?最初に頭に浮かぶのは、反対の兆候が見られたら反復をやめることです。

アップデート

パフォーマンスは気になりますが、今のところ答えは好きです。私はパフォーマンス中毒者ではありませんが、リストを扱うときはパフォーマンスを考慮するのが合理的だと思います。私の特定のユースケースでは、それは大したことではないと思いますが、この質問を完全にするために、それに対処するのは良いことだと思います。私の理解では、最小関数と最大関数にはO(n)のパフォーマンスがあります。これまでに提案された2つの回答は、O(2n)パフォーマンスですが、反対の符号が検出されたら終了するための短絡を追加する上記のルーチンは、最悪のO(n)パフォーマンスになります。考え?

4

4 に答える 4

21

あなたは機能を利用することができallます:-

>>> x = [1, 2, 3, 4, 5]

>>> all(item >= 0 for item in x) or all(item < 0 for item in x)
True

それが最もPython的な方法かどうかわからない。

于 2013-01-28T20:58:52.143 に答える
16

どうですか:

same_sign = not min(l) < 0 < max(l)

l基本的に、これはの最小要素と最大要素がゼロにまたがっているかどうかをチェックします。

これは短絡しませんが、Pythonループを回避します。ベンチマークのみが、これがデータの適切なトレードオフであるかどうか(およびこの部分のパフォーマンスが重要であるかどうか)を判断できます。

于 2013-01-28T20:59:15.637 に答える
3

代わりに、allを使用することもできますany。これは、最初の真のアイテムでも短絡するためです。

same = lambda s: any(i >= 0 for i in s) ^ any(i < 0 for i in s)
于 2013-01-28T21:46:56.003 に答える
2

を使用するのと同様にall、を使用できますany。これは、異なる符号が最初に出現したときにループを中断するため、パフォーマンスが向上するという利点があります。

def all_same_sign(lst):
    if lst[0] >= 0:
        return not any(i < 0 for i in lst)
    else:
        return not any(i >= 0 for i in lst)

0を両方のグループに属していると見なす場合は、少し注意が必要です。

def all_same_sign(lst):
    first = 0
    i = 0
    while first == 0:
        first = lst[i]
        i += 1
    if first > 0:
        return not any(i < 0 for i in lst)
    else:
        return not any(i > 0 for i in lst)

いずれの場合も、他の回答のように2回ではなく、1回リストを繰り返します。コードには、Pythonでループを繰り返すという欠点があります。これは、組み込み関数を使用するよりもはるかに効率的ではありません。

于 2013-01-28T21:52:19.463 に答える