如何确定列表(或可迭代)的数字是否都具有相同的符号?
这是我的第一个(幼稚)草案:
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)性能。想法?
答案 0 :(得分:18)
您可以使用all
功能: -
>>> x = [1, 2, 3, 4, 5]
>>> all(item >= 0 for item in x) or all(item < 0 for item in x)
True
不知道这是否是最蟒蛇的方式。
答案 1 :(得分:14)
怎么样:
same_sign = not min(l) < 0 < max(l)
基本上,这会检查l
的最小元素和最大元素是否跨越零。
这不会短路,但会避免Python循环。只有基准测试可以判断这是否是您数据的良好权衡(以及这件作品的性能是否重要)。
答案 2 :(得分:3)
而不是all
你可以使用any
,因为它也会在第一个真项上短路:
same = lambda s: any(i >= 0 for i in s) ^ any(i < 0 for i in s)
答案 3 :(得分: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中迭代循环的缺点,这比使用内置函数效率低得多。