Breaking out of a recursive function? - 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

Is my palindrome program correct and in an organized way?

def is_palindrome(x):
for i in range(0,len(x)):
x = x.lower()
if x[i::1] == x[::-1]:
return("%s Is a palindrome" %(x))
else:
return("%s Is not a palindrome" %(x))
print(is_palindrome('racecar'))
Here is my palindrome program I was just wondering is it right? I checked using the words racecar and madam and it says they are palindrome and I tested nonpalindrome words and it worked. Can someone tell me if it is wrong and then correct me on my mistakes or If its right but there is an easier way can you show me?
There is one major mistake there: you use a for loop which is always going to return in its first iteration. The if ... else ... statement always includes a return, therefore i will never reach anything else then 0 and you only check, if x[0::1] == x[::-1]. This might be desired behaviour, then however you should remove the for-loop.
just a advise, you don't need to use the for loop, as palindrome property say, reverse of the word is same as word, so you need to apply that way.
so your code be like this (one of all possible cases):
direct implementation
def is_palindrome(word):
return word==word[::-1]
this function will return True OR False based on if word is palindrome or not
implementation with the for loop ( check that first character is equal to last character , second to the second last character and so on)
def is_palindrome(word):
wlen = len(word)
for index in range(wlen//2):
if not word[i]==word[wlen-i-1]:
return False
return True
implementation
words = ['aa', 'racecar', 'hello']
for word in words:
if is_palindrome(word):
print("{} is palindrome".format(word))
else:
print("{} is not palindrome".format(word))

Checking if string is a palindrome returns wrong result

I am trying to check if a string is a palindrome, using recursion. I am currently just trying to develop simple cases.
My function takes as input a string. It then strips away the punctuation. The next thing I do is check if the first letter of the word is equal to the last letter of the word. If it is then it returns string one. If it isn't then it returns a second string.
def palindrome(word):
stringOne = "It's a palindrome"
stringTwo = "It's not a palindrome"
edit = word.strip("!").strip(",").strip("")
if edit[0] == edit[-1]:
return stringOne
else:
return stringTwo
print(palindrome("Yay!"))
The code is running. However, putting in the string "Yay!" (which is a palindrome) returns "It's not a palindrome." Any reason why my if statement isn't working?
Beyond the letter case issue that #RWRkeSBZ points out in the comments, this is a good example of where using a recursive helper function makes sense. Once you clean up the string to contain only letters, there's no reason to do so again upon recursion. Instead, we have a routine we call that deals with these issues and a more focused, recursive helper function that does the real processing:
def palindrome_recursive(letters):
if len(letters) <= 1:
return True
if letters[0] != letters[-1]:
return False
return palindrome_recursive(letters[1:-1])
def palindrome(phrase):
stringOne = "It's a palindrome"
stringTwo = "It's not a palindrome"
edit = phrase.strip("!,").strip().lower()
if palindrome_recursive(edit):
return stringOne
return stringTwo
print(palindrome("Able was I ere I saw Elba!"))

Refactor recursive string search to bisection search, hits max recursion depth

I have a very simple function which correctly searches if a character is in an alphabetical ordered string:
def isIn(char, aStr):
if len(aStr) == 0:
return False
if char == aStr[0]:
return True
else:
return isIn(char, aStr[1:])
Now I have tried to make it into a bisection search:
def isIn(char, aStr):
hi = len(aStr) - 1
lo = 0
mid = abs(hi+lo)/2
if len(aStr) == 0:
return False
if char == aStr[mid]:
return True
if char < aStr[mid]:
return isIn(char, aStr[:mid])
elif char > aStr[mid]:
return isIn(char, aStr[mid:])
It always exceeds the max recursion depth, even if aStr is just a few characters. I don't understand why it doesn't terminate. If my input aStr is len 4, it should search a mid value of 4+0/2 = 2, next time around 2+0/2 = 1, next time 1+0/2 = 0, next time len should = 0 and the recursion should terminate.
I've tried some strategically placed prints around, but can't figure it out.
This is homework.
The main issues here are that the pythonic behavior of numbers means that without any further indication of typing desired, 1/2 == 0, and that string slicing doesn't work like you're assuming.
Each time you have len(aStr) == 2, mid = 0, and a_string[0:] == a_string, meaning you're never paring down your string for the next recursion. You need to consider how to handle the base case of len(aStr) == 2, since it occurs here, or how to prevent you from passing down the same string over and over.
(hint: consider that a_string[index:] is inclusive of the character at index -- but you've already ruled out a_string[index] as being a potential match...)
If len(aStr)==1 or len(aStr)==2 and char>aStr[0], then you'll have mid=0 and this will recursively call isIn(char,aStr[0:]) which is exactly the same as isIn(char,aStr).
Since this is homework, I'll avoid spoiling too much. :)
The key of tackling recursion issues is making sure every possible input hits an escape clause - we want your functions to actually produce results.
The bisection will recurse every time splitting the string into halves - we we need to make sure our algorithm works properly handling strings of length zero and one.
You handled the zero-length strings nicely with the if len(aStr) == 0, so it must be something with one-character longs strings.
So, we're dealing with a string consisting of a single character.
What happens if the character is the one we're looking for? You're dealt with it promptly with your if char == aStr[mid]:.
But what happens if it isn't? The string is one character long, so we can answer it without going deeper into recursion.
Do you see it now?

Python-Recursion-New To Programming

I need to Check that every number in numberList is positive and implement the below
function using recursion. I'm stuck. Just learning recursion and I'm completely lost as I am very new to programming. Help!
def isEveryNumberPositiveIn(numberList):
foundCounterexampleYet = False
for number in numberList:
if(number <= 0):
foundCounterexampleYet = True
return not(foundCounterexampleYet)
Your function is not recursive because it never calls itself; a recursive version would look like
def all_positive(lst):
if lst:
return lst[0] > 0 and all_positive(lst[1:])
# ^
# this is the recursive bit -
# the function calls itself
else:
return True
# this keeps the function from looping forever -
# when it runs out of list items, it stops calling itself
This is a bad example to choose for a recursive function because (a) there is a simple non-recursive solution and (b) passing it a large list (ie over 1000 items) will overflow the call stack and crash your program. Instead, try:
def all_positive(lst):
return all(i > 0 for i in lst)
Your indentation is incorrect, but your thinking is correct, though the algorithm is not recursive. You could make it a bit more efficient though, by jumping out of the loop when a negative number is detected:
def isEveryNumberPositiveIn(numberList):
foundCounterexampleYet = False
for number in numberList:
if number <= 0:
foundCounterexampleYet = True
break
return not foundCounterexampleYet
then for example:
a = [1,-2,3,4,45]
print(isEveryNumberPositiveIn(a))
returns False
By the way, those parentheses forif and not are unnecessary.
With this sort of recursive problem, here is how you should think about it:
There should be a "basis case", which answers the question trivially.
There should be a part that does something that brings you closer to a solution.
In this case, the "basis case" will be an empty list. If the list is empty, then return True.
The part that brings you closer to a solution: shorten the list. Once the list get shortened all the way to a zero-length (empty) list, you have reached the basis case.
In pseudocode:
define function all_positive(lst)
# basis case
if lst is zero-length:
return True
if the first item in the list is not positive:
return False
# the actual recursive call
return all_positive(lst[with_first_value_removed]
Try to convert the above pseudocode into Python code and get it working. When you are ready to peek at my answer, it's below.
def all_positive(lst):
"""
Recursive function to find out if all members of lst are positive.
Because it is recursive, it must only be used with short lists.
"""
# basis case
if len(lst) == 0:
return True
if lst[0] <= 0:
return False
# recursive call
return all_positive(lst[1:])
There's several ways you can write this. One way would be to use lst.pop() to remove one element from the list. You could combine that with the if statement and it would be kind of elegant. Then the list would already be shortened and you could just do the recursive call with the list.
if lst.pop() <= 0:
return False
return all_positive(lst)
There is one problem though: this destroys the list! Unless the caller knows that it destroys the list, and the caller makes a copy of the list, this is destructive. It's just plain dangerous. It's safer to do it the way I wrote it above, where you use "list slicing" to make a copy of the list that leaves off the first item.
Usually in a language like Python, we want the safer program, so we make copies of things rather than destructively changing them ("mutating" them, as we say).
Here's one more version of all_positive() that makes a single copy of the list and then destroys that copy as it works. It relies on a helper function; the helper is destructive. We don't expect the user to call the helper function directly so it has a name that starts with an underscore.
def _all_positive_helper(lst):
"""
Recursive function that returns True if all values in a list are positive.
Don't call this directly as it destroys its argument; call all_positive() instead.
"""
if len(lst) == 0:
return True
if lst.pop() <= 0:
return False
return _all_positive_helper(lst)
def all_positive(lst):
"""
Return True if all members of lst are positive; False otherwise.
"""
# use "list slicing" to make a copy of the list
lst_copy = lst[:]
# the copy will be destroyed by the helper but we don't care!
return _all_positive_helper(lst_copy)
It's actually possible in Python to use a default argument to implement the above all in one function.
def all_positive(lst, _lst_copy=None):
"""
Return True if all members of lst are positive; False otherwise.
"""
if _lst_copy is None:
return all_positive(lst, lst[:])
if len(_lst_copy) == 0:
return True
if _lst_copy.pop() <= 0:
return False
return all_positive(lst, _lst_copy)
Recursion doesn't really help you with this. A better use for recursion would be, for example, visiting every node in a binary tree.

Using python 3 for recursive Boolean check if a list is sorted

I am trying to write a recursive function that does a Boolean check if a list is sorted. return true if list is sorted and false if not sorted. So far I am trying to understand if I have the 'base case' correct (ie, my first 'if' statement):
def isSorted(L, i=[]):
if L[i] > L[i + 1]:
return false
else:
return true
Am I correct with my initial if "L[i] > L[i + 1]:" as base case for recursion?
Assuming my 'base case' is correct I am not sure how to recursively determine if the list is sorted in non-descending order.
here is what I came up with. I designate the default list to 0; first check to see if first item is the last item. if not, should check each item until it reaches the end of the list.
def isSorted(L):
# Base case
if len(L) == 1:
return True
return L[0] <= L[1] and isSorted(L[1:])
This is how I would start. Write a function with the following signature:
function isSorted(currentIndex, collection)
Inside the function, check to see if currentIndex is at the end of the collection. If it is, return true.
Next, check to see if collection[index] and collection[index+1] are sorted correctly.
If they aren't, return false
If they are, return isSorted(currentIndex+1, collection)
Warning: this is a horrible use for recursion
No, the base case will be when you reach the end of the list, in which case you return true.
Otherwise, if the two elements you are looking at are out of order return false.
Otherwise, return the result of a recursive call on the next elements down the list.
I agree with #MStodd: recursion is not the way to solve this problem in Python. For a very long list, Python may overflow its stack! But for short lists it should be okay, and if your teacher gave you this problem, you need to do it this way.
Here is how you should think about this problem. Each recursive call you should do one of three things: 0) return False because you have found that the list is not sorted; 1) return True because you have reached your base case; 2) break the work down and make the remaining problem smaller somehow, until you reach your base case. The base case is the case where the work cannot be broken down any further.
Here is a broad outline:
def recursive_check(lst, i):
# check at the current position "i" in list
# if check at current position fails, return False
# update current position i
# if i is at the end of the string, and we cannot move it any more, we are done checking; return true
# else, if i is not at the end of the string yet, return the value returned by a recursive call to this function
For example, here is a function that checks to see if there is a character '#' in the string. It should return True if there is no # anywhere in the string.
def at_check(s, i):
if s[i] == '#':
return False
i += 1
if i >= len(s):
return True
else:
return at_check(s, i)
I wrote the above exactly like the outline I gave above. Here is a slightly shorter version that does the same things, but not in exactly the same order.
def at_check(s, i=0):
if i >= len(s):
return True
if s[i] == '#':
return False
return at_check(s, i+1)
EDIT: notice that I put i=0 in the arguments to at_check(). This means that the "default" value of i will be 0. The person calling this function can just call at_check(some_string) and not explicitly pass in a 0 for the first call; the default argument will provide that first 0 argument.
The only time we really need to add one to i is when we are recursively calling the function. The part where we add 1 is the important "breaking down the work" part. The part of the string we haven't checked yet is the part after i, and that part gets smaller with each call. I don't know if you have learned about "slicing" yet, but we could use "slicing" to actually make the string get smaller and smaller with each call. Here is a version that works that way; ignore it if you don't know slicing yet.
def at_check(s):
if s == '': # empty string
return True
if s[-1] == '#': # is last character '#'?
return False
return at_check(s[:-1]) # recursive call with string shortened by 1
In this version, an empty string is the basis case. An empty string does not contain #, so we return True. Then if the last character is # we can return False; but otherwise we chop off the last character and recursively call the function. Here, we break the work down by literally making the string get shorter and shorter until we are done. But adding 1 to the index variable, and moving the index through the string, would be the same thing.
Study these examples, until you get the idea of using recursion to break down the work and make some progress on each recursive call. Then see if you can figure out how to apply this idea to the problem of finding whether a list is sorted.
Good luck!

Categories

Resources