I create a function that compare with x and y variable. Inside the function has a lots of nested elif to compare the x and y then return integer. The problem is right now, when it runs at the certain elif statement, it didn't execute the statement although the statement is correct.
def convertTo(self, x, y):
if( x == 0 & y == 0):
return 0
if( x == 0 & y == 1):
return 1
if( x == 0 & y == 2):
return 2
if( x == 0 & y == 3):
return 3
if( x == 1 & y == 0):
return 4 # Didn't return this line even though x = 1 and y = 0
else
return None
def main():
self.convertTo(0,0)
self.convertTo(0,1)
self.convertTo(0,2)
self.convertTo(0,3)
self.convertTo(1,0) # return None? Why?
You're performing a chained equality comparison which is not doing what you think it does. The bitwise & is performed first as it has a higher priority than ==.
Replace:
x == 1 & y == 0
# 1 == 1 & 0 == 0
# 1 == 0 == 0 False!
With:
x == 1 and y == 0
See: Operator precedence
In Python, "&" and "and" do two different things. "and" is what you should be using, "&" is a binary operator.
if
a = 0011 1100
and
b = 0000 1101
then
a&b = 0000 1100
See http://www.tutorialspoint.com/python/python_basic_operators.htm
You should use and instead of &, as & is a bitwise and.
Chaining multiple conditions in Python is generally done with an if-elif-else statement like below:
if a and b:
# a and b both was true
elif a and not b:
# a was true, but b wasn't
else:
# none of the conditions matched
In your code, if it wasn't for the return statement in each if, and the fact that you are checking the same two variables, it would be possible for two if statements to evaluate to true.
if a:
# this will run if a was true
if b:
# regardless of a this will run if b was true
else:
# regardless of a this will only run if b was false
Also, take a look at this: https://docs.python.org/3/tutorial/controlflow.html
Related
I wrote a function:
# given a n x m grid return how many different ways there are to move from top left to
# bottom right by only being able to move right or down
def grid(n, m, memo = {}):
if f'{n},{m}' in memo:
return memo[f'{n},{m}']
if n == 1 and m == 1:
return 1
if n == 0 or m == 0:
return 0
memo[f'{n},{m}'] = grid(n,m-1,) + grid(n-1,m)
return grid(n,m-1,) + grid(n-1,m)
Recently I read a bit about short-circuiting in Python and I am trying to understand it further.
As I understand it does not provide any boost in runtime, just sort of syntax sugar.
For example:
1 < 2 < 3 # is True
1 < 2 and 2 < 3 # is also True
# hence
(1 < 2 < 3) == 1 < 2 and 2 < 3 # is True
I was wondering can I write my function with this kind of short-circuiting in my if statements?
I came up with this:
def grid(n, m, memo = {}):
if f'{n},{m}' in memo:
return memo[f'{n},{m}']
if (n or m) == 1:
return 1
if (n and m) == 0:
return 0
memo[f'{n},{m}'] = grid(n,m-1,) + grid(n-1,m)
return grid(n,m-1,) + grid(n-1,m)
Is there any smarter way of using the short-circuit here?
(1 < 2 < 3) is not short-circuiting - I think you misunderstood the meaning of the term. You are correct that it is merely syntax sugar - although it can produce some very weird results in obscure cases. (1 < 2 < 3) expands to (1 < 2) and (2 < 3) - the middle operand is copied to both and and is used for the joining operator.
Short circuiting occurs when python already knows the answer to a boolean expression, even before calculating both the inputs. For example
def false():
print("false")
return False
def true():
print("true")
return True
print(false() and true())
The output would be
false
False
Because when python sees False and, it already knows that the result is False (because and requires both operands to be True), so it doesn't bother running the second half of the line.
This real short circuiting does result in a performance boost, but since you can't turn off short circuiting, it doesn't really matter ¯\_(ツ)_/¯
if (n or m) == 1 is definitely not the same thing as if n == 1 or m == 1. The first if statement is equivalent to:
value = n
if not value:
value = m
if value == 1:
# do something:
Or expressed more succinctly:
if (n if n else m) == 1:
# do something
In other words, n or m only evaluates m if n is False (or 0 if n is an integer), otherwise the result of the expression is n.
What you want to avoid redundancy is:
if 1 in (n, m): # equivalent to: if 1 is either n or m:
Update: Demo
n = 4
m = 1
if (n or m) == 1:
print('if branch taken')
else:
print('else branch taken')
Prints:
else branch taken
if (n or m) == 1
evaluates to
if (<bool>) == 1 # e.g. if {True,False} == 1
which is probably not what you want, since it is essentially evaluating the truthiness of n or m.
Your existing code already captures the nature of short-circuiting;
if n == 1 and m == 1
will only evaluate the second argument m == 1 iff n == 1, or will otherwise short-circuit.
To your comment
As I understand it does not provide any boost in runtime, just sort of syntax suggar.
Well, actually it does provide a runtime boost if Python is able to skip evaluating what would otherwise be "expensive" conditions to evaluate because it is able to short-circuit early.
This question already has answers here:
Why does "a == x or y or z" always evaluate to True? How can I compare "a" to all of those?
(8 answers)
Closed 3 years ago.
I've written a fuction with lots of ELIF and OR statements. Code is working, but result is not what i'm expacting to get - absolutly the same values in DF table i'm cooperating with. What am I doing wrong?
def some_func(x):
if x == "aaaa" or "bbb" or "ccc" or "zzz":
return 1
elif x == "ddd" or "eee" or "fff" or "ggg":
return 2
elif x == "hhh" or "ppp" or "nnn" or "mmm":
return 3
else:
return 0
df.TABLE_name = df.TABLE_name.apply(some_func).astype('int64')
df['TABLE_name'].value_counts()
Out: 1 38133
Although your intuition is correct, the way your code is currently set up, it is not executing how you want.
Writing:
if x == "hello" or "world" does not check to see if x is equal to hello or equal to world. It checks to see if x is equal to hello and automatically returns true, because it essentially is evaluating if("hello"), which would always return true
Your code isn't working properly because your syntax is wrong. Consider making these changes:
def some_func(x):
if x == "aaaa" or x == "bbb" or x == "ccc" or x == "zzz":
return 1
elif x == "ddd" or x == "eee" or x == "fff" or x == "ggg":
return 2
elif x == "hhh" or x == "ppp" or x == "nnn" or x == "mmm":
return 3
else:
return 0
Rather than doing multiple O(n) comparisons in each if/elif statement consider using a set for single O(1) comparison instead:
def some_func(x):
if x in {"aaaa", "bbb", "ccc", "zzz"}:
return 1
elif x in {"ddd", "eee", "fff", "ggg"}:
return 2
elif x in {"hhh", "ppp", "nnn", "mmm"}:
return 3
else:
return 0
def is_even(x) :
while x:
if x==0:
return True
elif x==1:
return False
x-=2
print(is_even(5))
print(is_even(6))
output
False
None
If the x==0 is replace with x==2 it works fine. Please explain why returning True is not working for x==0.
In the last iteration, x is reduced to 0 so the while loop is not entered, and the function is terminated. Since it doesn't explicitly return anything, it implicitly returns None, which is a false-y.
You could use a single if inside the while loop and use the while's condiiton itself to indicate an even number:
def is_even(x) :
while x:
if x==1:
return False
x-=2
return True
If x = 0, then you fail your whilecheck and break out of the loop before you can check if x==0: return True.
You should instead use the modulo function, which returns the remainder of division.
3 % 2 == 1 # Odds
5 % 2 == 1
7 % 2 == 1
2 % 2 == 0 # Evens
4 % 2 == 0
6 % 2 == 0
Because when x == 0 it fails your while x check (0 is not truthy), so it exits the loop before it checks your condition again.
BTW the normal way to check parity is with the modulus (%) operator.
x % 2 == 0 # is_even
x % 2 != 0 # is_odd
If you use x as a condition while x that condition will be False if x equals 0.
The correct way should be:
def is_even(x):
while True:
if x==0:
return True
elif x==1:
return False
x-=2
Obviously this is a very weird way to check if a number is even, you can do:
def is_even(x):
return not bool(x%2)
In Python, integers have True and False values. Any integer that is not 0, will always evaluate True, and 0 will evaluate False.
In your code you are using a while loop, which only runs if the subsequent statement evaluates True. When you check while x, if the value of x is 0 (due to the calculation inside the loop), your statement will be the same as while False, which will not run the code inside.
To avoid this issue you can use the modulo operation, which gives you the remainder of an operation. Hence, x % 2 will return 0, if x is even, and 1 if it is odd. You can make a check on that and return the correct value in fewer lines, using fewer operations.
return (x % 2 == 0)
The above statement will return True if there is no remainder, and False if there is.
This should work
def is_even(x):
while x>=0:
if x == 0:
return True
elif x == 1:
return False
x -= 2
print(is_even(5))
print(is_even(6))
in your code the loop terminates when x reaches 0, put a condition such that the loop runs even when x is 0
cheers
Hi I have looked up a few recursive multiplication of 2 numbers in python, but none of them take into account the possibility of negative numbers or if they do they don't explain the entire steps.
I have coded the following the program but I am getting an error, can someone please let me know what is wrong with it?
def mult(a,b):
if a==0 | b==0:
return 0
elif a==1:
return b
elif a > 0 & b >0:
return b + mult(a-1,b)
elif a < 0 & b > 0:
return - b + mult(a+1,b))
elif a > 0 & b < 0:
return - b + mult(a-1, b))
else:
return -b + mult(a+1, b)
print(mult(-4,5))
| and & are bitwise operators, not logical operators, and their (relatively) high precedence means that a > 0 & b >0 is parsed as a > (0 & b) > 0, which is not what you want. Use or and and instead.
You have some python syntax errors and some sign problems. This works for mult(-4,5) and mult(5,-4).
def mult(a,b):
if a == 0 or b == 0:
return 0
elif a == 1:
return b
elif b == 1:
return a
elif a >0 and b > 0:
return b + mult(a-1,b)
elif a < 0 and b > 0:
return -b+mult(a+1,b)
elif a > 0 and b < 0:
return b+mult(a-1,b)
else:
return b + mult(a+1,b)
In your elif statement, you're using a bitwise "and" operator rather than the logical and operator. Everywhere that you have "&" replace it with "and"
I am pretty sure that this must be some glaringly stupid mistake by me. But can anyone explain what is wrong in this division code using recursion. I know there are a lot of alternatives, but I need to know what is wrong with this
def division(a, b):
x = 0
if a < b:
return x
else:
x += 1
return division(a - b, b)
return x
When I do division(10, 2), it gives me 0 as output
You always set your local variable x to 0.
Then if the dividend is smaller than the divisor you return that x which is of course 0.
On the other hand when the dividend is greater or equal to the divisor you increment x by 1 and do a recursive call with a decremented dividend which will of course lead to the first case at the end and still you return an x which holds the value of 0.
Note: Nonetheless your final return is not reachable since both your if and else branch contains a return.
So please try considering this solution:
def division(a, b):
if a < b:
return 0
else:
return 1 + division(a-b, b)
Update:
A possible solution for working with negative integers following python's round towards negative infinity division:
def division_with_negatives(a, b):
a_abs, b_abs = abs(a), abs(b)
if (a >= 0 and b >= 0) or (a < 0 and b < 0):
# branch for positive results
if a_abs < b_abs:
return 0
else:
return 1 + division_with_negatives(a_abs - b_abs, b_abs)
else:
# branch for negative results
if b_abs > a_abs or a_abs == b_abs:
return -1
else:
return -1 + division_with_negatives(a_abs - b_abs, -b_abs)
assert division_with_negatives(-4, 1) == -4 // 1
assert division_with_negatives(10, 2) == 10 // 2
assert division_with_negatives(1, -5) == 1 // -5
assert division_with_negatives(-3, -2) == -3 // -2
This might save you from RecursionError:
def div(x, y):
if y == 0:
return 0
elif x == y:
return 1
elif x < y:
if y * -1 == x:
return -1
elif x % y == 0:
return 1 + div(x - y, y)
else:
return 0
else:
if y < 0:
return 1 - div(x - y, -y)
else:
return 1 + div(x - y, y)
#Application
A = div(1, 2)
B = div(-9, 9)
C = div(3, 2)
D = div(-9, -3)
E = div(100, -2)
print(A) # 0
print(B) # -1
print(C) # 1
print(D) # 3
print(E) # -50
Your escape condition is if a < b. That means that for this function to terminate, this must be fulfilled to leave the recursion. However, because x is declared at the top of the function, only redefined inside the body of the else statement but never returned, the function will always terminate with a value of x = 0.
You should either set x = 1 + division(a-b,b) or return division(a-b,b) + 1 and remove the unreachable returnat the end.
def div(a, b, x):
if a < b:
return x
else:
x +=1
return div(a - b, b, x)
print(div(130, 10, 0))
# 13
This might work a little better for you:
def division(a,b,x=0):
if a < b:
return x
else:
x += 1
return division(a-b,b,x)
return x
Every time your function ran through a new recusion, you were setting x to 0. This way, it defaults to 0 if x is not specified, and should work like I think you want.
Also note that this will not work for negative numbers, but you probably knew that :)
With global you get:
def division(a,b):
global x
if a < b: return x
else:
x += 1
return division(a-b,b)
x=0
print (division(10,2))
But you have to set x to zero every time before call the division
i think this is best way, this way u can get floating answer also
def division(a,b):
if a == 0 or a == 1 or a == 2:
return b
else:
return a / division(a % b,b)
print(division(9,2))