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和/或正确的方法来做到这一点?首先想到的是一旦你有相反的迹象就停止迭代。

更新

到目前为止,我喜欢这些答案,尽管我想知道性能。我不是性能迷,但我认为在处理列表时考虑性能是合理的。对于我的特定用例,我认为这没什么大不了的,但为了这个问题的完整性,我认为解决它是件好事。我的理解是 min 和 max 函数具有 O(n) 性能。到目前为止,两个建议的答案具有 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

不知道这是否是最pythonic的方式。

于 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

与 using 类似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)

在任何情况下,您都将列表迭代一次,而不是像其他答案那样迭代两次。您的代码具有在 Python 中迭代循环的缺点,这比使用内置函数效率低得多。

于 2013-01-28T21:52:19.463 回答