Python: How to exit all the recursions in a recursive function [duplicate] - python

I'm wondering how to break out of a recursive loop to the main function. I am trying to do a simple palindrome exercise. The function should return True for "redivider" but the return True is being passed to is_pal() and the function isn't breaking. Short of adding a second variable to is_pal to track True/False, what is the proper way to break out of this recursive loop?
def first(word):
return word[0]
def last(word):
return word[-1]
def middle(word):
return word[1:-1]
def is_pal(str):
if len(str) == 1:
return True
if first(str) == last(str) and len(str) > 1:
is_pal(middle(str))
print is_pal("redivider")

One way to break out of a recursive function in Python is to throw an exception and catch that at the top level. Some people will say that this is not the right way to think about recursion, but it gets the job done. Furthermore, if the task is to identify "problem" elements in an array/array of arrays/ndarray etc., a break technique is convenient, because it stops the algorithm from continuing after the global solution has been identified.
def solve_problem(lst):
def solve_rec(l):
'''has impl. that may throw an exception '''
try:
solve_rec(lst)
return True
except:
return False

def is_pal(str):
if len(str) <= 1:
return True
if first(str) == last(str):
return is_pal(middle(str))
else:
return False
That way, if they don't match, False is returned; if it makes it all the way to the end, True is returned. I also eliminated a redundant conditional and checked for the edge-case of an even-length palindrome.

You don't "break" out of recursive functions. Trying to do so says you're thinking about them the wrong way. Currently your recursive call is ignoring the output, which means that the recursion is pointless; whatever is_pal(middle(str)) returns has no effect on the return value of your function.
A recursive algorithm solves the input problem by decomposing the problem into a smaller problem, getting the solution to the smaller problem recursively, and then using the smaller solution to construct a correct solution to the larger problem. You don't "break" out of the inner calls, you return a solution back up one level. You don't know (or need to know) whether you're in an inner call or a top level call. In either case, your function should do the same thing: return True if the argument is a palindrome, and False if it isn't.
The algorithm you're trying to implement is basically this:
If the string is of length 1, it's a palindrome (return True)
Otherwise, if the first character is the same as the last character, then the input is a palindrome if the middle characters are a palindrome.
So what this means is that once you've established the first and last characters are the same, the answer to "is my input a palindrome" is exactly the same as the answer to "are the middle characters a palindrome". You need to return that answer to fulfil your contract. So the recursive call should be return is_pal(middle(str)) rather than just is_pal(middle(str)). If this was a top level call, then that's the answer; if this wasn't a top-level call, then the outer call is going to need this answer to work out the answer to the outer problem (in this case, by simply returning it).
Btw, your algorithm also has some other problems.
You never return False, so the answer can never be False (in this case you happen to accidentally return None by falling off the end of the function if the first and last character don't match, and None will probably do as a stand in for False in most cases, but it's still not really correct).
If the string's length is zero rather than 1 (which will happen if an empty string is passed in or if a palindrome of even length is passed in once all the pairs of equal first and last characters are stripped off), then you don't return the correct answer, and in fact you try to get the first and last character of the empty string, which will cause an exception.

You can exit the program after printing the results using the exit() function.
That may not be a good practice, but it might be what you're looking for.

You're missing a return. Also, don't use str as a variable name. Last thing, the first and last functions could be named slightly better.
def first_letter(word):
return word[0]
def last_letter(word):
return word[-1]
def middle(word):
return word[1:-1]
def is_pal(word):
if len(word) == 1:
return True
if first_letter(word) == last_letter(word) and len(word) > 1:
return is_pal(middle(word))
print is_pal("redivider")

You need to return False in case they don't match and add a return statement. Also you will probably want to check against len(str)==0 and len(str)==1:
def is_pal(str):
if len(str) in [0, 1]:
return True
if first(str) == last(str) and len(str) > 1:
return is_pal(middle(str))
else :
return False

YOU CAN BREAK RECURSION BY RETURNING 1 in 'if' statement before you write your 'function()' 2nd time.
I mean that's what we do to find factorial !! RIGHT? :)

Related

Return in the function is working incorrect

Hey Stackoverflow community,
I am a python newbie.
So, I am trying to build the function any() from scratch. However the output I get is not what I expected. My code is working fine without the second if statement:
def anys(lst):
for i in range(0,len(lst)):
if bool(lst[i])==True:
return True
anys([False,True,False]) executes True as expected.
However, when I am adding a second if statement I get a different outcome:
def anys(lst):
for i in range(0,len(lst)):
if bool(lst[i])==True:
return True
if bool(lst[i])==False or len(lst)==0:
return False
anys([False,True,False]) executes False.
Can anyone help me what I am doing wrong? Any help would be greatly appreciated.
When you are using a return statement, the function will stop executing and, as instructed, return to the place where the function was called from. This means that the function will return at the first elemt in the list since it was False. If you want the function to return false if all of the elemts are false, I would recomend that you put the return False statement after the for loop.
To clearify, the loop starts with the first elemnt in the list, which in this case is False. The element satisfies the condition:
if bool(lst[i])==False or len(lst)==0:
And the function will then return False.
To answer the comment, if you loop through the entire list, and none of the elements are true (in other words "any"), you then want to return false instead.
def anys(lst):
for i in range(0,len(lst)):
if bool(lst[i])==True:
return True
return False
The code now goes through the list, if it ever encounters a True value, it returns True, however if none of the elements are True, it instead returns False.
The basic answer is that with both conditional return statements, you were always returning on the first iteration and ignoring the rest of the values from the list (or other iterable).
But aside from that, a few other hints that could be useful:
You do not need to loop by index number - just loop over the elements in the list directly.
To test whether an expression (here x) would be True if converted into a boolean, all you need to do is if x:
In the correct form with a single conditional return in the loop, it was returning None if no true values were found and the end of the function was reached. But the builtin any returns False in that situation, so an explicit return False is needed if you want to emulate this behaviour.
def anys(lst):
for x in lst:
if x:
return True
return False
Let us execute your second any() function line by line.
First element of input argument is False.
When you check first if condition, if bool(False) == True, it fails.
It reaches to your second if condition.
if bool(False) == False or len(lst) == 0, bool(False) == False is true hence this if condition is executed and your method returns False.

isPalindrome recursion string

why does this not work?
It works for False palindrome; however, for anything True it never returns True..
I don't understand why this function does not return True?
And how I should improve this same answer so that it returns True.
My logic was that after the function completes iterating through the entire string, it will return True.
def isPalindrome(string, i = 0):
if i == len(string):
return True
if string[i] != string[len(string)-1-i]:
return False
isPalindrome(string,i+1)
Problem is with your last line:
isPalindrome(string,i+1)
That last line will eventually resolve to either True or False -- but how is that value being returned? (It isn't.)
Try:
return isPalindrome(string,i+1)
Check out the visualization here
My hint would be check what you are returning (i.e. what does isPalindrome return).
If you want just the answer, it is here

Creating a function with a condition in Python

I need to create a function named 'Bernoulli' that should take 2 input variables 'rr' and 'p' and should return a value of 1 if rr is less than or equal to p and a value of 0 if rr is greater than p.
The code I have produced so far is this:
rr=float(input())
p=float(input())
def bernoulli(rr,p):
if rr<=p:
return 'X=1'
else:
return 'X=0'
I am not sure how correct this is.
Upon running tests I get this feedback:
Your program took too long to execute.
Make sure that it isn't waiting for input and that there is no infinite loop.
rr=float(input())
p=float(input())
def bernoulli(rr,p):
if rr<=p:
return 1
else:
return 0
x = bernoulli(rr,p)
print(x)
However, if you are simply checking if one number is bigger than the other, it might make more sense down the line to use True and False because comparing them will be a shorter line of code later on. if x == False That being in the logical sense that we understand true to be positive and false to be negative. You might forget which way round the 1 and the 0 are ordered :)
Swift answered this in the same way I would approach this. The reason your code is not executing, is because it is never used. You must call a function to use it.
Here is how I did it:
rr=float(input())
p=float(input())
def bernoulli(rr,p):
if rr<=p:
return 'X=1'
else:
return 'X=0'
function_response = bernoulli(rr,p)
print(function_response)

Why is my condition expression giving a syntax error?

def singleNumber(nums):
for num in set(nums):
return num if nums.count(num) != 2 #error occurs here
print(singleNumber([1,1,4,5,5]))
This follows the usual python condition expression format. I don't understand why it's giving me a syntax error here.
The purpose of this function is to find number that doesn't occur twice.
If you're going to actually execute a return, you must return something no matter what.
So you could try:
return num if nums.count(num) != 2 else None
However, that's not going to work in this case since it will return on the first check rather checking all the elements for what you want.
In other words, let's say the first element checked is the first 1 in [1,1,4,5,5]. It will work out that there are two copies of that value in the array and then return None, skipping the rest of the elements.
I'd probably rewrite it as:
if nums.count(num) != 2: return num
which basically does what you need in that, if you don't explicitly return something (i.e., all of the values occur twice), the caller gets None implicitly when the function exits.
If you're the type that dislikes implicit things, you can explicitly add return None at the end of the function, though it's not really necessary.
Because you forgot to write what the result should be if the condition is false.
return num if nums.count(num) != 2 else ...what?
And if you didn't want that then you should write a normal if statement instead.
When you use a ternary conditional operator both if and else part are mandatory.
return num if nums.count(num) != 2 else <missing???>

Understanding Recursion and Multiple Returns

I'm working my way through the MIT 6.00 class on OpenCourseWare and I'm having a little trouble with the lecture on recursion. I think I understand the basic idea, that you can break some problems down into smaller, repeatable problems. Where I'm having trouble is understanding how this works in the actual code. There is one specific example that I don't quite understand...
def toChars(s):
import string
s = string.lower(s)
ans = ''
for c in s:
if c in string.lowercase:
ans = ans + c
return ans
def isPal(s):
if len(s) <= 1:
return True
else:
return s[0] == s[-1] and isPal(s[1:-1])
def isPalindrome(s):
"""Returns True if s is a palindrome and False otherwise"""
return isPal(toChars(s))
This code is supposed to check if a string is a palindrome or not. I am a little lost on how isPal(s) works. Here's the steps as I'm reading them...
Check if s is one character or less, if it is return True.
If s has more than one character return a Boolean value (True or False) from the expression comparing the first and last character. So basically check if the first and last letter are the same.
AND return the result of the function run again with the first and last letters stripped from the string.
What is confusing me is the return s[0] == s[-1] and isPal(s[1:-1]) bit. I'm not sure I understand what it means to both return True/False based on the first expression AND return the function. Honestly I'm not even sure what returning the function actually means, I'm guessing it just runs the function again, but doesn't actually return any value. I also don't understand how this can actually tell if a string is a palindrome or not. Wouldn't it just keep hitting the second part of return s[0] == s[-1] and isPal(s[1:-1]) until the string, whether it was a palindrome or not, was reduced to 1 or 0 characters? The only thing I can think of is that returning a false value from return s[0] == s[-1] exits the function with a return of false? But I don't feel like that's actually how Python works, at least in my study so far I haven't run into anything saying that returning a False in a function would prevent the second part of the return statement from executing, which would call the function again regardless of whether the first and last letters where the same.
I'm kind of banging my head against the wall at this point, so any insight would be really appreciated!
Perhaps the best way is to go step by step with the values for that line that is confusing you.
return s[0] == s[-1] and isPal(s[1:-1])
Assuming the String you're testing for is "ABCDBA", here is the sequence of calls
return s[0] == s[-1] and isPal(s[1:-1]) #evaluate to ("A" == "A" and isPal("BCDB")) - need to go deeper
return s[0] == s[-1] and isPal(s[1:-1]) #evaluate ("B" == "B" and isPal("CD")) - need to go deeper
return s[0] == s[-1] and isPal(s[1:-1]) #returns ("C" == "D")
Note that in the last line we didn't evaluate for isPal because of short-circuiting - we know that False and X where X can be True or False is always False. Read more about that here.
At the last line we're 4 functions deep into isPal. Since the last line doesn't require us evaluate for isPal() again, we start "rising to the surface" back to the original invocation of isPal which was at
def isPalindrome(s):
"""Returns True if s is a palindrome and False otherwise"""
return isPal(toChars(s))
One clarification which can help you understand what's going on: return ...X and ...Y means: Compute the value of X. If the value is false, return it, otherwise compute the value of Y, and return it.
More info about the short-circuit, lazy behavior (i.e. not evaluating Y if not needed) of the and and or operators in Python: https://docs.python.org/release/2.7/reference/expressions.html#boolean-operations
So that statement doesn't make the function return two values (X and Y), but one value which is the logical AND of X and Y: it's true iff both X and Y are (evaluated to) true.
Also it's worth distinguishing function from function call. There can be many active calls to the same function, with different arguments, local variables etc., so their return values can also be different (as soon as they return). When a function calls itself, that's called recursion. When a function call returns, execution continues in the caller, which can be the same function (but of course a different, upper-level function call) in case of recursion.
If you run the isPal function on "heeeeh" with print statements:
def isPal(s):
if len(s) <= 1:
return True
else:
print s[0],s[-1]
return s[0] == s[-1] and isPal(s[1:-1])
print isPal("heeeeh")
You get:
h h
e e
e e
True
as each char at index s[0] and s[-1] are equal through each recursive call as the string is a palindrome.
Running it on "aeeee":
def isPal(s):
if len(s) <= 1:
return True
else:
print s[0],s[-1]
return s[0] == s[-1] and isPal(s[1:-1])
print isPal("aeeeeh")
You get :
a h
False
As as soon as s[0] and s-[1] are not equal the functions ends and returns False as it cannot be a palindrome if the chars are not equal.
I'll add my explanation, maybe this will help you.
First things first:
def toChars(s):
import string
s = string.lower(s)
ans = ''
for c in s:
if c in string.lowercase:
ans = ans + c
return ans
will simply take some text and turn it all to lower case, character by character.
Next is:
def isPal(s):
if len(s) <= 1:
return True
else:
return s[0] == s[-1] and isPal(s[1:-1])
To understand this part you ask yourself a question, what is a palindrome and what are ways to know if word or sentence is one.
In this example approach is: palindrome is word or sentence where its characters in same distance from beginning and from the end are the same characters.
So how to check that? Well, first if your word is just one letter or shorter then it's a palindrome.
Then you check if letters at the beginning and the end of your word are the same.
You remember the result as true or false and strip your word from letters you already checked and repeat the process until your word is 1 or less characters long and check if every result of comparison was true.
Example:
Foob->foob
f=b? NO, false
Example 2:
Fbof->fbof
f=f? Yes, true,
bo
b=o? No, false.
true and false = false, so the word is not a palindrome
Example 3:
Fobof->fobof
f=f? Yes, true,
obo,
o=o? Yes, true
b
len(b) = <=1 ? Yes, true,
true and true and true = true, so the word is a palindrome.
Hope it helps, ask if you need more thorough explanation, I'll try to help, no worries, i struggled with recursion at the beginning as well.

Categories