Reputation: 921
I've made a small function which, given a tuple, compares if all elements in this tuple is of the same sign.
E.g., tuple = [-1, -4, -6, -8]
is good, while [-1, -4, 12, -8]
is bad. I am not sure I've made the smartest implementation, so I know this is the place to ask.
def check_consistent_categories(queryset):
try:
first_item = queryset[0].amount
if first_item < 0:
for item in queryset:
if item > 0:
return False
return True
else:
for item in queryset:
if item < 0:
return False
return True
except:
return False
Upvotes: 3
Views: 282
Reputation: 82992
def all_same_sign(iterable):
# Works with any iterable producing any items that can be compared to zero.
# Iterates through the input no more than once, and this fact is immediately
# obvious from the code.
# Exits as soon as a bad combination has been detected.
pos = neg = zero = False
for item in iterable:
if item > 0:
pos = True
elif item < 0:
neg = True
else:
zero = True
# Adjust the following statement if a different
# treatment of zero is required.
# Redundant parentheses added for clarity.
if (pos and neg) or zero:
return False
return True
Upvotes: 1
Reputation: 161
Using the principal that multiplying your numbers gives a positive result if they all the same, else negative,
import operator
def all_same_sign(intlist):
return reduce(operator.mul, intlist) > 0
>>> all_same_sign([-1, -4, -6, -8])
True
>>> all_same_sign([-1, -4, 12, -8])
False
This doesn't handle zeros though...
Upvotes: 0
Reputation: 304355
Here is one that works fine with generators etc. too
def all_same_sign(ints):
ints = iter(ints)
first_is_positive = next(ints) > 0
return all( (x>0) == first_is_positive for x in ints)
If ints
is empty, you get a StopIteration exception.
This version gorups 0 with the negative numbers. Use >=
if you wish to group with the positive numbers instead
Upvotes: 1
Reputation: 838696
This might help you:
def all_same_sign(ints):
return all(x < 0 for x in ints) or all(x > 0 for x in ints)
You may want to change < and > to <= and >= depending on how you want to treat 0.
Upvotes: 14
Reputation: 3838
After @EOL's solution, but works without list indexing or iterating multiple times.
def all_same_sign(sequence):
items = iter(sequence)
try:
first = items.next() > 0
except StopIteration:
return True
return all((item > 0) == first for item in items)
This also occurred to me, but doesn't take advantage of all/any short-circuiting:
def all_same_sign(sequence):
return len(set(item > 0 for item in sequence)) <= 1
Upvotes: 3
Reputation: 461167
Why not take advantage of the fact that if all numbers are the same sign, then the sum of the absolute value of each individual number will be equal to the absolute value of the sum of each number?
def check_sign(queryset):
return abs(sum(queryset)) == sum(map(abs, queryset))
Case 1: All numbers have the same sign
a = (-1, -4, -8)
sum(a) = -13
abs(sum(a)) = 13 # the absolute value of the tuple's sum
map(abs, a) = [1, 4, 8]
sum(map(abs, a)) = 13 # the tuple's sum of each element's absolute value
Both methods yield 13, so the signs are the same.
Case 2: Not all numbers have the same sign
b = (-1, 4, 8)
sum(b) = 11
abs(sum(b)) = 11 # the absolute value of the tuple's sum
map(abs, b) = [1, 4, 8]
sum(map(abs, b)) = 13 # the tuple's sum of each element's absolute value
The methods yield different numbers (11 and 13), so the signs are not all the same.
Upvotes: 1
Reputation: 21041
If your numbers are sorted you only need to compare the ends. If not you could sort them:
def same_sign(numbers):
numbers = sorted(numbers)
#if numbers[0]==0: return True Uncomment if you consider 0 positive
if numbers[0]*numbers[-1]>0: return True
return False
If you changed this to >=0
zero would be considered sign neutral. I'm not sure if this is a better implementation than the current answers, but it could be faster for large sets of data.
Upvotes: 0
Reputation: 94565
Here is a nice pythonic way of doing this (using all()
):
from math import copysign
sign = lambda x: copysign(1, x) # Sign function
def check_consistent_categories(sequence):
main_sign = sign(sequence[0])
return all(sign(y) == main_sign for y in sequence)
(for Python 2.6+, which introduced the math.copysign()
function). This solution considers that 0 is positive.
Mark Byers' solution is more flexible, though, and it is also arguably more legible.
Upvotes: 1
Reputation: 47642
Just one unrelated nit, since you are doing this:
try:
[...]
except:
[...]
You are ignoring all
of the exceptions, be very careful my friend, this will be hiding lots of bugs, instead always be precise while doing exception handling e.g:
try:
[...]
except IndexError:
# Handle out of index
except IOError:
# Handle I/O error
etc. Keep this in mind while coding a larger python application.
Upvotes: 1