Feedback on implementation of function which compares integer signs in Python - python

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

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.

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

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.

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.

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))
Example Showing Details of the Math
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.

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

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

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.

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...

Related

Python: Binary Search - "Find the first occurrence"

having a bit of trouble with this one. I have included what I have below. When I submit it, it keeps saying "Program timed out" for some reason. I am not sure what to do next. It works to a certain degree, ie, some tests work, not the last test just doesn't work. What do you suggest?
I have included a screenshot of the question, as well as what I have so far.
Here is the note (pseudocode) from class, I just need to modify this to modify it to print the first occurance of the target in the ordered_list. If the target does not exist in the list, it must return None.
Thank you in advance!!
The Question:
You are to write the code of a Python function
binsearch first(ordered list, target)
that, given a nonempty ordered list of items and a target item, all of the same type, returns the index of the first occurrence of the target in the list, if the target is in the list, and None otherwise.
For example, the call binsearch first([1, 3, 3, 7, 9], 3) should return 1 since the first 3 is at index 1. Similarly, the call binsearch first([1, 3, 3, 7, 9], 9) should return 4, and the call binsearch first([1, 3, 3, 7, 9], 5) should return None.
You may not assume anything about the type of the items, other than that they are orderable. For example, items could be strings and the call binsearch first(["Alice", "Bob", "Chloe", "Chloe", "Dave"], "Chloe") should return 2.
Your program will be evaluated for efficiency and style. For full credit, it may only make a single test for equality (it may only have a single “==” comparison which, additionally, may not be within any loop). That is, the only equality test happens at the end of execution, just before returning.
Restrictions: Recursion is not allowed for this problem. allowed to use any operations other than
Furthermore, you are not
, − , // , × , < ,
and (once) ==
Of course, all builtins and library functions related to search are also disallowed: you have to do the coding yourself.
def binsearch_first(ordered_list, target):
left = 0
right = len(ordered_list) - 1
count = 0
while left <= right:
mid = (left + right) // 2
count = count + 1
if ordered_list[mid] == target:
while mid > 0 and ordered_list[mid - 1] == target:
mid = mid - 1
return mid
elif target < ordered_list[mid]:
right = mid - 1
else:
left = mid + 1
return None
Find the first occurrence
The only operator that works with string and integer is <.
We have to make use of the fact that it is an ordered list - arranged in increasing order.
def binsearch(orderedlist,target):
candidate = 0
for i in range(len(orderedlist)):
if orderedlist[i] < target:
candidate = candidate
else:
if i+1 < len(orderedlist):
if orderedlist[i] < orderedlist[i+1]:
#it is an ordered list so if i+1 is not bigger than i, it must be equal
candidate = candidate
else:
candidate = i
break # can you use break?
if orderedlist[candidate] == target:
return candidate
else:
return None
I am not a CS student hence cannot comment on the effectiveness of the program, but you can achieve your goal by using a simple for loop
def binsearch_first(ordered_list, target):
i=0
for ele in ordered_list:
if ele == target:
return i
break
else:
i+=1
return None
Result of this is:
>>> binsearch_first([1, 3, 3, 7, 9], 3)
1
>>> binsearch_first(["Alice", "Bob", "Chloe", "Chloe", "Dave"], "Chloe")
2
Regards

How to use recursion to implement "Finding the maximum value in an array" in Python?

How to use recursion to implement "Finding the maximum value in an array" in Python ?
The following is a simple test code I wrote
I want to do it by recursion
I'm learning algorithms, learning recursion.
Thanks very much!
def max(list):
if list == []:
msg = "List: ..."
return msg
max = list[0]
for item in list[1:]:
if item > max:
max = item
return max
data = [8,2,-690,4,12,-320,0, 98]
print(max(data))
If you want to use recursion, it's very important to define carefully the end cases.
The maximum of the elements of a list is, obviously, either the first element or the maximum of the rest of the list: it's the greatest of the two values. That's actually the recursion you are looking for.
But what happens when there is no first element? You have an empty list, and an undefined behaviour. Why not maximum([]) = 0? Because it would lead to some inconsistency: maximum([-1]) = greatest(-1, maximum([])) = greatest(-1, 0) = 0. (You could also try maximum([]) == -math.inf, but this won't be very intuitive!)
What if the rest of the list is empty? No problem, you have just one element and it is the maximum.
Just translate this analysis into code:
def maximum(xs):
if len(xs) == 0:
raise ValueError()
elif len(xs) == 1:
return xs[0]
else:
u = xs[0]
v = maximum(xs[1:])
return u if u >= v else v # greatest(u, v)
More on maximum([])
I will try to give a value to maximum([]). I repeat the argument above. For any given n, maximum([n]) = greatest(n, maximum([])) = n. This implies that, for every n, maximum([]) <= n. The only value that meets this condition is -math.inf. Why not define maximum([]) == -math.inf? Imagine you create a minimum function. For symetrical reasons, you will have to define minimum([]) == math.inf. Hence it exists a list l0 = [] such that minimum(l0) > maximum(l0). No one would accept such a possibility.
What should we do now? There are two main possibilities: defensive programming or use a contract. In defensive programming, the function will check the arguments it has received, and fail if one of these arguments is not correct. That's what I did:
def maximum(xs):
if len(xs) == 0:
raise ValueError()
...
If you use a contract, you will basically say: if you give this function an empty list, then the behaviour is undefined. It might return any value, crash, loop forever, .... Here, you would have something like:
def maximum(xs):
"""!!! xs must not be empty !!!"""
...
It seems the same, but there is a huge difference. You can use, for implementation reasons, -math.inf as the return value for maximum([]), because it is now clear that it doesn't have any meaning. Someone who tries to check if minimum(l0) <= maximum(l0) for l0 = [] clearly breaks the contract and won't be surprised by the result. Of course, if you want to make it robust, you will write:
def maximum(xs):
"""PRECONDITION: xs must not be empty"""
assert len(xs) != 0 # can be disabled at runtime at your own risks
_maximum(xs)
def _maximum(xs):
"""no precondition here"""
if len(xs) == 0:
return -math.inf
else:
u = xs[0]
v = _maximum(xs[1:])
return u if u >= v else v # greatest(u, v)
Try this (using recursion, as requested by the OP):
def largest(arr):
if len(arr) == 2:
return arr[1] if arr[1] > arr[0] else arr[0]
else:
return largest([arr[0], largest(arr[1:])])
No built-in functions are used (such as max) because the OP has stated that they don't wish to use any built-in functions.
The else part of the function returns either the first element of the list or the largest number in the list (excluding the first element) depending on whichever number is larger.
Each time the else part is executed, the largest(arr[1:]) bit checks which number is largest inside arr without the first element. This means that, at one point, arr will contain two elements. When it does so, a one-line if statement is used to compare the two elements and returns the larger element.
Eventually, the code recurses back to the first level and returns the largest element.
I would write max and max_all
from math import inf
def max (a, b):
if a > b:
return a
else:
return b
def max_all (x = -inf, *xs):
if not xs:
return x
else:
return max (x, max_all (*xs))
max_all can be called with any number of arguments
print (max_all (8, 2, -690, 4, 12, -320, 0, 98))
# 98
Or use * to unpack arguments
data = [ 8, 2, -690, 4, 12, -320, 0, 98 ]
print (max_all (*data))
# 98
It even works when 0 inputs are given
print (max_all ())
# -inf
def Maximum(list):
if len(list) == 1:
return list[0]
else:
m = Maximum(list[1:])
if m > list[0] else list[0]:
return m
def main():
list = eval(raw_input(" please enter a list of numbers: "))
print("the largest number is: ", Maximum(list))
main()
The simplest way
max and list are built-in functions. So you want to avoid using those identifiers yourself.
Here's a simple version that uses recursion:
#/usr/bin/python
def largest(arr):
if not arr:
return None
else:
r = largest(arr[1:])
if r > arr[0]:
return r
else:
return arr[0]
data = [8, 2, -690, 4, 12, -320, 0, 98]
print(largest(data))

Function to Create a Zigzag Array in Python

I'm trying to create an array of positive and negative integers, representing distances north and south of a location - I need to see the elements of the array in zigzag order.
This means that the largest member appears first, the smallest member appears second, and the remaining elements alternate between the larger members decreasing from the largest and the smaller members increasing from the smallest.
I.e. the array [1, 3, 6, 9, -3] becomes [9, -3, 6, 1, 3].
I'm trying to complete the function wiggleArrangeArray, which takes one argument, an integer array of n integers.
Required Input Format, Constraints, and Output Format
I'm not sure how to say
"if the item in the array is larger than the other items in the array, display it first."
"if the item is smaller than the other items in the array, display it second."
"then alternate between the next largest numbers, and the next smallest numbers"
def wiggleArrangeArray(intArr):
for i in intArr
#if i > other items in intArr
#display that i at index value 0
#if i < other items in intArr
#display that i at index value 1
#if i < i at index value 0 and > other items in intArr, display it next
#if i > i at index value 1 and < other items in intArr, display it next
#repeat last two lines for continuing values
Please help if possible. Here's a link to the solution in C++ but I need it in Python. Thanks.
Edit: The function needs to work with the following tests:
f = open(os.environ["OUTPUT_PATH"], "w")
_intArr_cnt = int(raw_input())
_intArr_i=0
_intARR = []
while _intArr_i < _intArr_cnt:
_intArr_item = int(raw_input());
_intArr.append(_intArr_item)
_intArr_i+=1
res = wiggleArrangeArray(_intArr);
for res_cur in res:
f.write( str(res_cur) + "\n" )
f.close()
The altered C++ code
Note the algorithm you provided does calculate some sort of zigzag, but it is not the zigzag you are looking for. For future reference I will leave it here.
In the C++ code you provided, they only look for a sequences that satisfies a < b > c < d > e < f, you are looking however for a sequence with the 1-max, 1-min, 2-max, 2-min,...
Your link provides you a solution which you can copy nearly verbatim in Python. You only define a swap function:
def swap(arr,i,j):
t = arr[i]
arr[i] = arr[j]
arr[j] = t
Next you can simply modify the code:
def zigZag(arr):
n = len(arr)
# Flag true indicates relation "<" is expected,
# else ">" is expected. The first expected relation
# is "<"
flag = True
i = 0
while i<= n-2:
if (flag): # "<" relation expected
# If we have a situation like A > B > C,
# we get A > B < C by swapping B and C
if arr[i] > arr[i+1]:
swap(arr,i,i+1)
else: # ">" relation expected
# If we have a situation like A < B < C,
# we get A < C > B by swapping B and C
if arr[i] < arr[i+1]:
swap(arr,i,i+1)
flag = not flag # flip flag
i += 1
Mind that this is rather un-Pythonic, so you can simply improve it like:
def swap(arr,i,j):
arr[i],arr[j] = arr[j],arr[i]
def zigZag(arr):
n = len(arr)
for i in range(len(arr)-1):
if not i&1:
if arr[i] > arr[i+1]:
swap(arr,i,i+1)
elif arr[i] < arr[i+1]:
swap(arr,i,i+1)
return arr
Here tuple assignment is used to swap elements in the list, a range is used to iterate over the indices, we can furthermore use an elif instead of an if in an else, and for I've abandoned the flag by using a modulo check.
Your zigzag function
You can simply solve the problem by sorting the list, and using two pointers that each time emit the most left, the most right and walk towards each other. In other words something like:
def zigZag(arr):
srt = sorted(arr)
left = 0
right = len(srt)-1
result = []
while left < right:
result.append(srt[right])
right -= 1
if left < right:
result.append(srt[left])
left += 1
return result
Here Python implementation example.
Sort your data in reversed order (9, 6, 3, 1, -3)
Split by two lists (9, 6) (3, 1, -3)
Iterate over both (using zip_longest) first one from start, second in reverse order (9, -3), (6, 1) (None, 3)
Unpack tuples created by zip_longest (chain(*zip...)) so you get iterable data (9, -3, 6, 1, None, 3)
Remove None value in case if the list has an odd number of elements (if x is not None)
Example:
from itertools import zip_longest, chain
def zig_zag_array(data):
data = sorted(data)
mid = len(data) // 2
return [
x for x in chain(*zip_longest(data[mid:][::-1], data[:mid])) if x is not None
]
Test:
if __name__ == "__main__":
data = [1, 3, 6, 9, -3]
expected = [9, -3, 6, 1, 3]
output = zig_zag_array(data)
assert output == expected, f"Odd length: {output=}"
data = [1, 3, 6, 9, -3, 0]
expected = [9, -3, 6, 0, 3, 1]
output = zig_zag_array(data)
assert output == expected, f"Even length: {output=}"
print("PASSED")

Insert value in Incremental List not working

Context:
This code is really simple, I´m just new to python. I have an incremental list of numbers, all I need to do is check if there is any missing value, and if I do, insert -1 in that position, example:
If I have a list with values [1,2,4,5], I want it to become [1,2,-1,4,5].
If I have a list with values [1,4,5], I want it to become [1,-1,-1,4,5].
Simple, yet I can´t do it properly on python.
My code:
id: The list I want to modify.
i, j, and z: Counters.
MyRange: I can´t show the real name of the variable (I don´t own the code), but the range is correct.
z=0
for i in MyRange:
value = id[i]
value2 = id[i+1]
j=z
//This while is here because I try not to compare a value with -1
//(I think this is the problem)
while value == -1:
j=j-1
value = id[j]
if(int(value)+1 == int(value2)):
if(value2 != -1):
id.insert(i,-1)
z=z+1
This code identifies any missing value, but then fills the rest of the list (From the missing value to the last value with -1).
Any help would be apprecciated. Thank you and sorry for any english mistakes.
One somewhat easy way to do this is to make a set of the numbers. Then you can count from the lowest to the biggest and look for the number in the set. If it's there, you're all good. If it's not there, then yield a -1.
def fill_range(initial_range, fill_vallue):
smallest = initial_range[0]
biggest = initial_range[-1]
items = set(initial_range)
for i in range(smallest, biggest+1): # use xrange on python2.x
if i in items:
yield i
else:
yield fill_value
You might use this generator function like this:
print(list(fill_range([1,2,4,5], -1)))
If you haven't seen a generator function before, they're worth learning about but the answer above might be slightly confusing. Here's a version which accumulates a list and then returns it at the end:
def fill_range(initial_range, fill_vallue):
result = []
smallest = initial_range[0]
biggest = initial_range[-1]
items = set(initial_range)
for i in range(smallest, biggest+1):
if i in items:
result.append(i)
else:
result.append(fill_value)
return result
You might also notice that the if else suite could be replaced here pretty easily by a conditional expression...
You need only one additional variable to keep track of missing elements of the sequence.
def insert_minus_ones(lst):
new_lst = []
last = lst[0] - 1
for e in lst:
while (last + 1) != e:
new_lst.append(-1)
last += 1
new_lst.append(e)
last += 1
return new_lst
The code above works for any sequences of numbers:
>>> insert_minus_ones([1,2,4,6,10])
[1, 2, -1, 4, -1, 6, -1, -1, -1, 10]
>>> insert_minus_ones([-5,-4,-3,2])
[-5, -4, -3, -1, -1, -1, -1, 2]

min() arg is an empty sequence

I'm trying to find minimum element in matrix row, but there are two conditions:
1) it must be > 0
2) and this point must be not visited(is_visited[k] is False)
I'm trying to do next:
min(x for x in matr_sum[i] if x > 0 if is_visited[k] is False )
But there is an error: min() arg is an empty sequence
The full block of code:
for k in range(4):
if matr_sum[i][k] == min(x for x in matr_sum[i] if x > 0 if is_visited[k] is False ) and i!=k:
return k
How to resolve it? Or should I write my min() function? Because it works with one condition:
min(x for x in matr_sum[i] if x > 0)
But with two conditions, it doesn't work.
If you want to avoid this ValueError in general, you can set a default argument to min(), that will be returned in case of an empty list. See described here.
min([], default="EMPTY")
# returns EMPTY
Note that this only works in Python 3.4+
There is no problem with the syntax. It's certainly unusual to have two if clauses, but it's allowed. Consider:
print(min(x for x in range(1,300) if x % 3 == 0 if x % 5 == 0))
Output:
15
However:
print(min(x for x in range(1,300) if x % 2 != 0 if x % 2 != 1))
Output:
ValueError: min() arg is an empty sequence
There are no integers that are both odd and even, so there are no values for min to see, so it throws an exception.
I deduce that in your code, there are no values that pass both conditions. Python doesn't allow you to compute "the minimum of no values", mainly because it makes no sense.
You have to decide what you want to do in the case where there is no minimum because there are no values greater than 0. For example, if you don't want to return k in that case then I might re-write your code something like this:
for k in range(4):
if k != i and is_visited[k] is False:
if matr_sum[i][k] > 0 and matr_sum[i][k] == min(x for x in matr_sum[i] if x > 0):
return k
It might not be obvious why this helps, but assuming matr_sum[i] is a list or similar, then once we know matr_sum[i][k] > 0 then we know the generator passed to min isn't empty, so we won't get an exception. Whereas if matr_sum[i][k] <= 0, then it certainly isn't equal to the smallest positive value, so there's no need to compute the min at all. Another way to write that would be:
if matr_sum[i][k] > 0 and not any(0 < x < matr_sum[i][k] for x in matr_sum[i])
Actually, I'd normally write if not is_visited[k], but I leave it as is False since I don't know whether changing it would change the behaviour of your code.
Try this - it creates the list of x values xs and then only tries to find the min if xs is non-empty. You may need to add some logic to handle the case that xs is empty, depending on what your code is doing.
for k in range(4):
if is_visited[k] is False and i != k:
xs = [x for x in matr_sum[i] if x > 0]
if xs and matr_sum[i][k] == min(xs):
return k
Just use and operation for concatenate tow if statement :
min(x for x in matr_sum[i] if x > 0 and if is_visited[k] is False and i!=k)

Categories

Resources