Python-Recursion-New To Programming - python

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.

Related

What's the different between calling function with and without 'return' in recursion?

I tried to create recursive function for generating Pascal's triangle as below.
numRows = 5
ans=[[1],[1,1]]
def pascal(arr,pre,idx):
if idx==numRows:
return ans
if len(arr)!=idx:
for i in range (0,len(pre)-1,1):
arr+=[pre[i]+pre[i+1]]
if len(arr)==idx:
arr+=[1]
ans.append(arr)
pascal([1],arr,idx+1)
a = pascal([1],ans[1],2)
return a
The output I got was an empty list [ ]. But if I add return when calling pascal as
return pascal([1],arr,idx+1)
the output was correct [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]].
As I understand, a should have been assigned by return ans. Then why a failed to get an answer when calling pascal without return and why return is necessary in this case?
When you have recursion, you usually combine the returns in some way. Could be a sum, like fibonacci:
fibonacci(n+1) = fibonnaci(n)+fibonacci(n-1)
Or appending a line to a matrix, like your case. Anyway, if you don't have a return, you have no information to combine! Consider the fibonnaci case without return:
def fibonnaci(n):
if n<2:
return 1
fib_ans = fibonnaci(n-2)+fibonnaci(n-1)
In this case, if I called fibonnaci(0) or fibonnaci(1) the output would be 1, like you return ans if idx == numRows, but if I called fibonnaci(2), then the variable fib_ans would receive 2, which is the expected answer, but it would be available outside the scope of the funtion. Python "would add" return None to the end of my function, just below the fib_ans attribution. So, I need to return fib_ans
Well as far as i know, if you want to get a value back you need the "return" statement...
The point is if you don't have "return", you will be getting no values back...
Hopefully this helps..
For all algol languages that has a return keyword it exits the nearest function completely and the result of it is the result of the expression of the return argument. eg.
def test(v):
if v == 0:
return someFun(10)
...
If v is zero the result of the function is the value returned by someFun(10). The rest of the function denoted by ... is never executed unless v is nonzero.
If we write the same without return:
def test(v):
if v == 0:
someFun(10)
...
Now, when v is zero someFun(10) is still called, but the value returned by it is discarded and in order for it to have any true meaning someFun needs to do some side effects, like printing, storing values, updating object. In addition all the rest of the function denoted by ... is then continued once someFun(10) is done.
For Python and many other languages not having a return at all doesn't mean it doesn't return anything. In Python there is an invisible return None in the last line of every function/method.
When you do pascal([1],arr,idx+1), you are doing the recursive call but then discarding the value which it returns. If you want to return it to the caller, then you need to use explicitly return pascal(...).
In fact recursion is not necessary in this example anyway. You could easily refactor your code to use a simple for loop. For example:
def pascal(numRows):
ans = [[1]]
for _ in range(1, numRows):
pre = ans[-1]
arr = [1]
for i in range(0,len(pre)-1,1):
arr+=[pre[i]+pre[i+1]]
arr+=[1]
ans.append(arr)
return ans
print(pascal(5))
(I'm using the name _ here as the for loop variable according to convention because it is a dummy variable not used inside the loop, but you could use something else e.g. row if you prefer.)
The above is as close to the original code as possible, but you should also consider using arr.append(value) in place of arr += [value] -- this would be the normal way to append a single value to a list.

I have a generator in my Python function; how can I return a modified list?

A little background: I've been trying to code a "Sieve of Eratosthenes" algorithm. At the request of some fine (and very patient) programmers on the StackOverflow Python chatroom, I did some reading on the enumerate() function and found a way to incorporate it into my code (yes, I'm very much a novice here). So far, my (workable; returns expected response) code looks like this:
def SieveErat(n):
numbers = [False]*2+[True]*(n-1)
for index, prime_candidate in enumerate(numbers):
if prime_candidate == True:
yield index
for x in xrange(index*index, n, index):
numbers[x] = False
primes = []
for x in SieveErat(150000):
primes.append(x)
print primes[10002]
Needless to say, the enumerate() function makes coding this much, much less awkward than whatever nested loops I had before. However, I fear that I'm not understanding something about enumerate(), because when I tried to shorten this code by including the appending into the function, I kept getting errors- namely,
File "SievErat.py", line 13
return numbers
SyntaxError: 'return' with argument inside generator
I've also tried appending all the True elements inside the list numbers to a initialized list primes, but found no luck.
Any hints or advice would be very much welcomed.
This has nothing to do with enumerate you are trying to return something in a generator which before python 3.3 is illegal, and from 3.3+ it means something entirely different.
I'd recommend you leave your function a generator if you may use it without needing a list back, and if you want list results then just call list() on the return value:
primes = list(SieveErat(150000)) #this replaces loop with .append
But to understand what went wrong, if your function still has the yield statement in it then it must return a generator object, if you don't want it to return a generator object then remove the yield statement all together:
def SieveErat(n):
numbers = [False]*2+[True]*(n-1)
for index, prime_candidate in enumerate(numbers):
if prime_candidate == True:
#yield index #no yield statement if you want to return the numbers list
for x in xrange(index*index, n, index):
numbers[x] = False
return numbers #return at end
However this would then return a list of True and False instead of the numbers that are True, you can instead hold a separate list with all the prime numbers and .append to it everytime you would yield something:
def SieveErat(n):
numbers = [False]*2+[True]*(n-1)
result = [] #start with no results
for index, prime_candidate in enumerate(numbers):
if prime_candidate == True:
results.append(index) #instead of yield index
for x in xrange(index*index, n, index):
numbers[x] = False
return results
But this feels like a step backwards from a generator, personally I'd just keep what you have posted and cast the result to a list.

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!

Breaking out of a recursive function?

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? :)

Halt a recursively called function

I'm trying to halt the for loop below once values (x,y) or (z,2) have been returned so that the value i doesn't keep increasing, and simply halts when the if or elif condition is first
def maxPalindrome(theList):
# students need to put some logic here
maxcomplist = theList[:]
maxcomplist.reverse()
control = len(theList) - 1
# exit if maxPalindrome is True
for i in range(control):
if maxcomplist[:] == theList[:]:
x = 0
y = len(theList)
return (x, y)
break
elif maxcomplist[i:control] == theList[i:control]:
successList = theList[i:control]
z = i
w = len(theList) - z - 1
return (z, w)
How can I accomplish this?
As I wrote in a comment already: that function isn't a recursive one at all.
Recursion means, that a function calls itself to complete it's purpose. This call can be indirect, meaning that the function uses helper function that will call the first function again.
But your code doesn't cover both cases.
A recursive function always have a certain architecture:
the first thing after being called should be to test, if the primitive case (or one primitive case among options) has been reached. if so, it returns.
If not it will compute whatever is needed and pass this results to itself again,
untill the primitive case is reached, and the nested function calls will finish in one after the other.
One well-known usage of recursion is the quicksort algorithm:
def quicksort(alist):
if len(alist) < 2:
return alist # primitive case: a list of size one is ordered
pivotelement = alist.pop()
# compute the 2 lists for the next recursive call
left = [element for element in alist if element < pivotelement]#left = smaller than pivotelemet
right = [element for element in alist if element >= pivotelement]#left = greater than pivotelemet
# call function recursively
return quicksort(left) + [pivotelement] + quicksort(right)
So the "stop" must be the return of a primitive case. This is vital for recursion. You cannot just break out somehow.
I don't understand the question - if I get it right, that what you want already happens. If you return, the function stops running.
Some comments in addition to this answer:
As well, I cannot see where the function is called recursively, nor what
exit if maxPalindrome is True
means. (Is this a comment, maybe?)
Besides, the maxcomplist[:]==theList[:] does not make much sense to me, and seem to be a waste of time and memory, and to have this comparison in each iteration loop doesn't make it faster as well.

Categories

Resources