在Python中检查列表中所有数字是否为同一符号?

5

我如何判断一个数字列表(或可迭代对象)中的所有数字符号是否相同?

以下是我最初的(幼稚的)草稿:

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)

有没有更符合Python代码规范且正确的方法?首先想到的是,在遇到相反符号时停止迭代。
更新
我喜欢目前为止给出的答案,尽管我对性能有些疑虑。我不是一个追求性能的狂热分子,但我认为在处理列表时考虑性能是合理的。对于我的特定用例,我认为这不是什么大问题,但为了完整地回答这个问题,我认为需要解决这个问题。据我所知,min和max函数具有O(n)性能。到目前为止提出的两个答案具有O(2n)性能,而上面的程序在检测到相反符号时添加了短路以使其最差也只有O(n)性能。你怎么看?

O(n)O(2n)是完全相同的东西。任何解决这个问题的算法都将具有o(n)最坏情况性能,因为它必须检查每个元素。最后,如果您关心性能,我建议您在典型数据上对候选方法进行基准测试。 - NPE
4个回答

22
您可以使用all函数:-
>>> x = [1, 2, 3, 4, 5]

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

不确定这是否是最符合Python风格的方式。


Python有带符号的零吗? - mgilson
@mgilson。实际上,我不知道。我在Python方面经验很少。 :( - Rohit Jain

16

怎么样:

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

基本上,这检查最小元素和最大元素是否跨越零。

虽然这不会短路,但避免了Python循环。只有基准测试可以告诉您这对于您的数据是否是一个好的权衡(以及这段代码的性能是否重要)。


3

可以使用any代替all,因为它在第一个真项目处短路:

same = lambda s: any(i >= 0 for i in s) ^ any(i < 0 for i in s)

1
all 在第一个 False 上短路;any 在第一个 True 上短路。我不理解。 - DSM
我相信 all 也会短路,可以看一下这个回答的评论:https://dev59.com/EXE85IYBdhLWcg3w2Hbs#2580142 - User

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)

无论如何,与其他答案中的两次迭代相比,您只需一次迭代列表。您的代码的缺点是在Python中迭代循环,这比使用内置函数要低效得多。


很好的观点,没有考虑Python中迭代与使用内置功能之间的差异。 - User

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接