Recursively checking for odd or even - python

In this code:
def is_even(x):
if x == 0:
return True
else:
return is_odd(x-1)
def is_odd(x):
return not is_even(x)
print(is_even(2))
print(is_odd(2))
I keep going through this in my head and wondering how it's working. It seems to me that eventually x in is_even(x) will return True every time. However, when I run the code, it works perfectly fine and returns True and False appropriately. Can someone explain how that's happening?
I understand the basic concept of recursion and fully understand how the famous factorial example works. However, this one is hard for me to wrap my head around.
Feeling inept right now...

It always helps to decompose a recurrence relation till you find its base case.
is_even(2) => return is_odd(1)
=> return not is_even(1)
=> return not is_odd(0)
=> return not not is_even(0)
=> return not not True
=> return True ---- (1)
is_odd(2) => return not is_even(2)
=> return not True [from (1)]
=> return False
In general, from your recurrence functions, it is easy to observe that is_even(n) will return [not not not ... n times] True, while is_odd(n) will return [not not not ... n - 1 times] True. So the number of nots and hence the final expression depend on n (aha!). Well, that's certainly a roundabout way of asking whether
n % 2 == 0

Add a couple of print statements and you will see what it is doing:
from __future__ import print_function
def is_even(x):
if x == 0:
print('True')
return True
else:
return is_odd(x-1)
def is_odd(x):
print('not', end=' ')
return not is_even(x)
>>> is_even(5)
not not not not not True
False
>>> is_odd(5)
not not not not not not True
True

Like in most cases it might be helpful to include simply prints to follow the execution:
def is_even(x):
print('check if {} is even'.format(x))
if x == 0:
return True
else:
return is_odd(x-1)
def is_odd(x):
print('check if {} is odd'.format(x))
return not is_even(x)
Then in your cases:
>>> print(is_even(2))
check if 2 is even
check if 1 is odd
check if 1 is even
check if 0 is odd
check if 0 is even
True
>>> print(is_odd(2))
check if 2 is odd
check if 2 is even
check if 1 is odd
check if 1 is even
check if 0 is odd
check if 0 is even
False
So basically it decrements the number until it's 0. The point is just how many nots have been accumulated in the is_odd calls. If it's an even number of nots then the result will be True, otherwise False.

That's true; the recursion is supposed to end inside is_even.
And when that will happen, you'll know that the number you have is 0.
Now lets go backwards. This final state will be achieved by two cases - direct call to is_even(0) or a call from is_odd(0). In the first case - the result is all good. In the second - the result will be returned to the is_odd function, negated, and therefore will be falsy - giving a correct result.
Now, here the missing piece comes - the recursion: in order to reach this state, we need to decrease the argument each time, passing it through the opposite function - and that's exactly what we get with return is_odd(x-1).
Note: eventually this recursion leads to a chain of negations of the value True returned by the is_even. This chain is of length x where x is your number, and therefore odd or even in correspondence.
Therefore, the following code will do the same (lacking the is_odd nice side effect):
def is_even (x):
res = True
while x:
res = not res
x -= 1
return res

I think that all the other answers are great but potentially the easiest way to understand the problem is how many times the answer will get "not"ed. Every time it passes through the is_odd function a not will be added on to the final answer. True will always be returned but for even numbers, there will always be an even number of nots which cancel each other out, but for odd numbers they will always have an odd number of nots and therefore return false.

Related

wondering why my list has bigger number than second argument function return False?

def greater(list, num)
for x in list:
if x > num:
return True
else:
return False
as you can see in my code, i am trying to write a function that return True if list_number contained number that is bigger than second argument, otherwise return False.
but here is confusing:
when i input: greater([1, 2, 3], 2), and its return False. I am wondering why is that? the first argument contained 3 and its bigger than 2.
any helps and explanations will be appreciated.
You want to have it return at the end of the function. Right now, you have it return after checking only the first number. Try this:
def has_gt(list_number,number):
for x in list_number:
if x > number:
return True
return False
A property of if/else is that if one runs, the other doesn't. But in both cases, one runs. In your code, this snippet:
if x > number:
return True
else:
return False
Means that it will check if the number is bigger than the number in question. If it is, it will return True. If not, it will return False. A return call instantly ends the processing of a function, so it will stop checking after that.
To summarize, your code loops through the target list. It checks the first number, one, and sees if it is bigger than two. It is not, so the code returns False, instantly ending the function. So, your function just ended in a False, which is what it returned.
The change I made was that it returns False at the end of the code. This means that it will check each value for being greater than the target. If it finds any value greater than the target, it will end processing, with a return value of True. If the code hasn't returned by the time it reaches the end of the function, it will return False because of the statement at the end of the function.
Actually what happens is the else part also runs just after comparing the number (here 2) with the first element in the list_number (here 1) thus returns false.
So the solution is you need to let the for loop first run completely which is stopped by the else statement.
def has_gt(list_number,number):
for x in list_number:
if x > number:
return True
return False

I want to write a function in python which returns true if all the digits are even

The function is all_even in which you input an int and it returns bool. It returns true if all the digits are even. e.g. all_even(2224) gives true and all_even(1362) gives false.
I wrote the code but it is not working properly.
This is what I have:
def is_very_even(num: int) -> bool:
even = False
strnum = str(num)
for ch in strnum:
if int(ch)% 2==0:
even = True
return even
The code gives true even if the num has a single even num and the rest are odd e.g all_even(231) is true which is supposed to be false. Can somebody tell me what is wrong with it.
You could use a recursive approach (without converting to a string):
def allEven(N): return True if N==0 else N%2==0 and allEven(N//10)
output:
allEven(246) # True
allEven(123) # False
Note that the issue with your function is that you set even to True as soon as you encounter an even digit. If there is an odd digit after that, your even variable remains True. This will tell you that "at least one" digit is even, not that they are all even.
You are checking if all the numbers are even. So first assume that it's true, all the numbers are even and set even = True. Then check if there is any odd number in the string. If there is, then set even = False
Now, if there is any odd number in the string, even will be False and therefore we can verify it.
def is_very_even(num: int) -> bool:
even = True
strnum = str(num)
for ch in strnum:
if int(ch)% 2 !=0:
even = False
return even
This code can also be improvised like this. We don't need to keep checking if we found a single odd number. We can just return false immediately. And if all the numbers checks out but none returns false, then it must be an all even string.
def is_very_even(num: int) -> bool:
for ch in str(num):
if int(ch)% 2 !=0:
return False
return True
I would solve it like this:
def is_very_even(s) -> bool:
return all(int(x) % 2 == 0 for x in str(s))
This converts every character to an integer and checks if it is even with modulo. This is processed in a so called generator expression.
Then we use the builtin all method to check if the generator delivers only True values.

Is this function logical or am I over thinking? Loop errors for finding even number

Which code segment should replace the statement pass in the function hasEvenNumber which returns True if n contains an even number and False otherwise?
def hasEvenNumber(n):
for i in n:
pass # Replace this section with below options
return result
The question screenshot
This is an actual university exam question. I find it very badly structured and since my classmates are new too, nobody dared to voice out fearing to make a fool of themselves.
Firstly n was not given, but judging that n will be used in a for loop. n therefore, would be an iterable. I think none of the 4 options applies, but please advise me if I'm wrong.
Option 1:
if i % 2 == 0:
result = True
else:
result = False
This will only work if iterable only contains 1 item e.g [1,2,1] will not work since the result of 2 as even number that should return true will be replaced as the loop proceed to next iteration.
[1,2,1,1] False # Wrong, should be true
[1,1,1,2] True
[2] True
Option 2:
if i % 2 == 0:
result = True
break
else:
result = False
break
Worse than above, this will only iterate the first item and break regardless.
[1,2,1,1] False # Wrong, should be true
[1,1,1,2] False # Wrong, should be true
[2] True
Option 3:
if i % 2 == 0:
result = True
break
Function will have runtime error if no even number is found, the variable result will not be assigned.
[1,2,1,1] True
[1,1,1,1] Runtime Error
[2] True
[1] Runtime Error
Option 4:
if i % 2 != 0:
result = False
break
Same as above, runtime error. No variable will be assigned if all even numbers.
Personally, as the question asked to check if n contains even number. I would have written something like this.
# Break and exit loop once even number is found. Otherwise continue.
if i % 2 == 0:
result = True
break
else:
result = False
Unfortunately, this is not an option. Apologies if this is the wrong place to post this, but any advice would be gladly appreciated, and could possibly change the fate our my current school cohort.
Yes, you are right and little bit overthinking.
Third option is right and it is kinda assumed here that result is set to False in the beginning.
Also, your solution can be optimised by declaring result = False once in the beginning and then you can eliminate the else block completely.
If you want it to end when an even number is found, option 3.

How to find if there are 2 elements of same value consecutively in a list?

For example,
[1,3,3,5] should return True while [1,3,1,3] should return False.
I am looking for a simple solution using loops.
I tried the following:
def conseq(nums):
for i in range (len(nums)):
if nums[i]==nums[i+1]:
return True
break
else:
return False
The first time your function encounters 2 consecutive numbers which are different, it returns False. Returning from a function ends that function immediately, the function does not continue after that. This is also why the break is not necessary.
Another issue with your code is that once you reach the final number, nums[i + 1] will access out of the bounds of the array. That's why you should iterate over len(nums) - 1 rather than len(nums) - there's no reason to check the final number because there's nothing after it.
def conseq(nums):
for i in range(len(nums) - 1):
if nums[i]==nums[i+1]:
return True
# Only return False once we've exhausted all numbers.
# Since we didn't return True so far - it means there are
# no consecutive equal numbers, so we can safely return False
return False
the return ends the function, so here it will stop the processing as well
your true statement mostly works, and the break is unnecessary
you don't want the else statement until after the for loop ends (it returns False only if everything else has been parsed)
Also the way you parse through the code, nums can't access nums[i+1] when you're at the final nums so you need the range len(nums) - 1
If you feel like putting an else that does nothing, you can with a single semicolon or pass I believe, but the else is unnecessary here
def conseq(nums):
for i in range (len(nums)-1):
if nums[i]==nums[i+1]:
return True
else:
;
return False
You can't return False until the loop is done (since the match may be in the part of the list you haven't checked yet). And the break after return will never happen (since return ends the function and everything in it).
Enumerate list without last (to avoid try catch for i+1 being out of range) then compare each item with next one and return True if they are same. After loop return False because none are similar consequtively (returns break functions)
def function(number_list):
for i, item in enumerate(number_list[:-1]):
if item == number_list[i+1]:
return True
return False
def conseq(nums):
for i in range (len(nums)):
if nums[i]==nums[i-1]:
return True
return False
I modified your Code. Please check and let know if useful
def conseq(nums):
flag=True
for i in range (len(nums)-1):
if nums[i]==nums[i+1]:
print(True)
flag=False
break
else:
continue
if(flag):
print(False)
nums=[1,3,3,5]
nums1=[1,3,1,3]
conseq(nums)
conseq(nums1)
We have many solutions here already. I have tried out using numpy without a loop:
>>> import numpy as np
>>> f = np.array([1,3,3,5])
>>> (np.where(np.diff(f) == 0)[0]).astype('bool')[0] #check if we have any difference of two elements 0?
True

Is this recursion is posible?

Can someone please explain to me how this piece of recursive code is working? Because there is only one if statement which checks if variable x is equal to zero and returns true if the value is equal to zero.
And the other part is just upon calling each other.
def is_even(x):
if x == 0:
return True
else:
return is_odd(x-1)
def is_odd(x):
return not is_even(x)
print(is_odd(17)) # outputs true
print(is_even(23)) # outputs false
This pair of mutually recursive functions makes use of three facts:
0 is even
x is even if x - 1 is odd.
x is odd if x - 1 is even.
1 is odd because 1 - 1 == 0 is even.
2 is even because 2 - 1 == 1 is odd.
And so on.
This is not an efficient way to determine if an arbitrary value n is even or odd, but it is a logically correct way. (Assuming the argument is always a natural number, anyway. Passing a negative integer as an argument to either results in infinite recursion, as the base case will never be reached.)
I want to give a simpler answer to follow along with. Think about the stack trace. I'll abbreviate is_even and is_odd as IE and IO respectively.
IO(17)
NOT[IE(17)]
NOT[IO(16)]
NOT[NOT[IE(16)] = IE[16]
IO(15)
...
This is basically checking if alternating descending numbers starting from the input value are even and odd all the way down to 0. Note that if we start with a true statement (like IO(17)) then every line contains a true statement - if we started with a false statement, every line ends up with a false statement. Following the pattern we see here, we see that the final state can therefore end up as
IE(1) -> IO(0) -> NOT[IE(0)] = NOT[True] = False # as expected!
OR
IO(1) -> NOT[IE[1]] = NOT[IO[0]] = NOT[NOT[IE(0)] = NOT[NOT[True]] = True # likewise!

Categories

Resources