Related
I am learning coding by myself. I am taking learning recursive function from online resources, and as an exercise, I came across this one exercise where I am tasked to create a recursive function to see if numbers in the list are in order. The exercise says not to use loops and not to use variables, so I can learn recursive function better for the future.
def is_increasing(lst):
if not (lst[0]) < lst[1]:
return False
else:
return is_increasing(lst[1:])
when I input is_increasing([1,2,12,24]) in the console.
The errors says:
IndexError:list index out of range
What am I doing wrong that is showing this error?
You need a stop condition (or base case) for every recursive function, otherwise it won't stop: in your case, the stop condition is if the list contains one elements or less, it's always sorted:
def is_increasing(lst):
if len(lst) <= 1: return True # Base case
if not (lst[0]) < lst[1]:
return False
else:
return is_increasing(lst[1:])
You didn't take the recursion far enough. You are assuming that a list will have at least two elements, but that's not true for empty and singleton lists. (Plus, at no point did you ever attempt to return True.)
The true base case is a list with fewer than 2 items, which is trivially sorted. Otherwise, you can check whether the first 2 elements are in order, then recursively check the rest of the list.
def is_increasing(lst):
if len(lst) < 2:
return True
else:
return lst[0] < lst[1] and is_increasing(lst[1:])
When implementing a recursive function, there is always one special case which has to be handled differently: how does the recursion stop?
The implementation show here correctly reduces the problem of solving an input of size N to a problem of size N-1:
def is_increasing(lst):
if not (lst[0]) < lst[1]:
return False
else:
return is_increasing(lst[1:])
What is missing is handling the situation where the size is 0 or 1. Therefore:
def is_increasing(lst):
if len(lst) < 2:
return True # That is always sorted
# BTW this is correct only if it is supposed to be descending,
# oherwise it should be lst[0] > lst[1]
if not lst[0] < lst[1]:
return False
else:
return is_increasing(lst[1:])
Your function never returns True. That's not directly the cause of the error, but that's related to it.
For a recursive function that returns a bool, you need two base cases, not just one: one that returns True and one that returns False.
So when should it return True? What is the relevant base case? It is when the list is too small to fail: a list that is of length 1 or 0 is always increasing, technically. And in that case, there is no lst[1], which causes the IndexError. So this is the solution:
def is_increasing(lst):
if len(lst) < 2:
return True
elif lst[0] >= lst[1]:
return False
else:
return is_increasing(lst[1:])
(You also had a mistake where you compare not lst[0] with lst[1], I fixed that for you ;)
I'm trying to write a program that returns set of all subset sum of a list. I must use list comprehension and recursion.
Example:
[1,2,3,10]
return set([0,1,2,3,4,5,6,100,101,102,103,104,105,106])
I write code:
def function(L):
if len(L) == 0:
return []
return list((L[index] + rest) for index in range(len(L)) for rest in function(L[:index])+L[index+1:])
This code returns sum of subsets but only 2 or more elemental subset.
Example
[1,2,3,4,100]
return [3,4,5,6,101,102,103,104,105,106]
This is change that seems to yield the right answer:
def function(L):
if len(L) == 0:return []
return L+list((L[index] + rest) for index in range(len(L)) for rest in function(L[:index])+L[index+1:])
So my recursive function is too look in a list and see if an item is repeated in a list already. Ex. L = [1,2,3,4,3] return True. I've completed it but im not allowed to use the 'in' function but dont know a work around.
Edit: the only built in functions i am allowed to use are len, and the index and splice operators.
def has_repeats(L):
if L == []:
return False
elif L[0] in L[1:]:
return True
else:
return has_repeats(L[1:])
return False
You may consider using recursion to compare the list in reversed order that their indexes are the same, since index at default returns the first occurrence, like this:
def has_repeats(L):
if len(L) <= 1:
return False
if L.index(L[-1]) != len(L) - 1:
return True
return has_repeats(L[:-1])
Usage:
has_repeats([1, 2, 3, 4, 3])
True
has_repeats([1, 2, 3, 4, 0])
False
So basically check the index of last item len(L) - 1 will be the same as L.index which should return the first occurrence, if they don't match, there is a duplicate before the last item, and do it recursively.
An alternative is to compare the first and last elements in the list, progressively discarding from both ends.
def has_repeats(L):
if len(L) < 2:
return False
return L[0] == L[-1] or has_repeats(L[:-1]) or has_repeats(L[1:])
This is inefficient because of the double recursion, but it works for short lists.
I'm trying to do a lab work from the textbook Zelle Python Programming
The question asked me to "write and test a recursive function max() to find the largest number in a list. The max is the larger of the first item and the max of all the other items." I don't quite understand the question from the textbook.
def Max(list):
if len(list) <= 1:
else:
return list[0]
else:
m = Max(list[1:])
return m if m > list[0] else list[0]
def main():
list = eval(raw_input(" please enter a list of numbers: "))
print("the largest number is: ", Max(list))
main()
Or maybe I'm suppose to open a txt file with numbers in it and then use recursive?
I believe recursive works like this
def function()
> if something:
>>return 0
>else:
>>return function()
Your understanding of how recursion works seems fine.
Your if-block is messed up, you have two elses to one if and the alignment is out. You need to remove your first else and un-indent everything below the if one level. eg:
def Max(list):
if len(list) == 1:
return list[0]
else:
m = Max(list[1:])
return m if m > list[0] else list[0]
def main():
list = eval(raw_input(" please enter a list of numbers: "))
print("the largest number is: ", Max(list))
main()
I post a different solution approach of the problem. Most of the answers manipulate the list using the slice operator in each recursive call. By the time the exercise does not provide a strict function prototype to be used, I also pass as function parameter the length of the list.
Suppose that we try to find and return the maximum element from a sequence S, of n elements.
Function prototype: Max(S, n)
Base case: If S contains only one item, return it. (Obviously the only item in the sequence is the max one.)
Recur: If not the base case, call Max each time for one less item, that is call Max(S, n-1). We then store the returning value to a variable called previous that indicate the previous element from the sequence and check that value with the next element in the sequence, which is the right most element in the current recursive call, and return the max of these values.
A recursion trace of the above procedure is given in the following figure. Suppose we try to find the max from a list that contains [5, 10, 20, 11, 3].
Note: To help you further, keep in mind that we recursively iterate the list from the right most element to the left most one.
Finally here is the working code:
def find_max_recursively(S, n):
"""Find the maximum element in a sequence S, of n elements."""
if n == 1: # reached the left most item
return S[n-1]
else:
previous = find_max_recursively(S, n-1)
current = S[n-1]
if previous > current:
return previous
else:
return current
if __name__ == '__main__':
print(find_max_recursively([5, 10, 20, 11, 3], 5))
Note: The recursive implementation will work by default only with sequences of 1000 most elements.
To combat against infinite recursions, the designers of Python made an
intentional decision to limit the overall number of function
activations that can be simultaneously active. The precise value of
this limit depends upon the Python distribution, but a typical default
value is 1000. If this limit is reached, the Python interpreter
raises a RuntimeError with a message, maximum recursion depth exceeded.
Michael T. Goodrich (2013), Data Structures and Algorithms in Python, Wiley
To change the default value do:
import sys
sys.setrecursionlimit(1000000)
here is one more approach to solve above problem
def maximum(L):
if len(L) == 1:
return L[0]
else:
return max(L[0],maximum(L[1:]))
so example input and output:
L= [2,4,6,23,1,46]
print maximum(L)
produces
46
The basic approach is this.
If the list contains only a single element, that element is the max. Return it immediately.
Otherwise, the list contains multiple elements. Either the first element in the list is the maximum, or it is not.
The maximum of the first element is simply the first element in the list.
Recursively call Max on the rest (all but first element) to find the maximum of those elements.
Compare the results from step 3 and 4. The result is the number that is greater. Return it.
Right now you have some syntax errors. For example, you have two else clauses for a single if, and the indentation looks funny. You can only have one else for an if block. But if you follow these instructions, you should have a working algorithm.
def Max(lis,maxx=-float("inf")):
if len(lis) == 1: #only one element in lis
return maxx if maxx>lis[0] else lis[0] #return lis[0] if it's greater than maxx
else:
m=lis[0] if lis[0]>maxx else maxx # m = max(lis[0],maxx)
return Max(lis[1:],m) #call Max with lis[1:] and pass 'm' too
print Max([1,2,39,4,5,6,7,8]) #prints 39
print Max([1,2,3,4,5,6,7,8]) #prints 8
These solutions fail after certain list size.
This is a better version:
def maximum2(a, n):
if n == 1:
return a[0]
x = maximum2(a[n//2:], n - n//2)
return x if x > a[0] else a[0]
def maximum(a):
return maximum2(a, len(a))
maximum(range(99999))
>>> 99998
One simple way would be to sort the list first then use indexing.
Here's a function that would work:
a = [1,233,12,34]
def find_max(a):
return sorted(a)[-1]
def find_max(my_list, max):
if len(my_list) <= 1:
return max
else:
if my_list[0] > max:
return find_max(my_list[1:], my_list[0])
else:
return find_max(my_list[1:], max)
if __name__ == '__main__':
my_list = [1, 5, 16, 9, 20, 40, 5]
print(find_max(my_list, my_list[0]))
def find_max(arr):
"""find maximum number in array by recursion"""
if arr == []: # if its an empty array
return 0
if len(arr) == 1: # if array has only one element
return arr[0]
else: # get max of first item compared to other items recursively
return max(arr[0], find_max(arr[1:])) # 1: means all other excluding 0th element
def main():
print(find_max([2,3,5,6,7,1])) # will print max - 7
if __name__ == "__main__":
main()
You can also do it in this way:
def maximum(data, start, stop):
if start >= stop:
return data[start]
else:
if data[start] >= data[stop - 1]:
return maximum(data, start, stop - 1)
else:
return maximum(data, start + 1, stop)
def recursiveMax(a):
if len(a) == 1:
return a[0]
else:
return a[0] if a[0] > recursiveMax(a[1:]) else recursiveMax(a[1:])
Test:
print(recursiveMax([1, 2, 15, 6, 3, 2, 9]))
print(recursiveMax([98, 2, 1, 1, 1, 1, ]))
TLDR; This code will also work when the list passed to the function is empty!
#jam's answer is amazing. However, I found some problems with the conditions, I think #Blender was hinting at it.
That code will fail in the case when the list passed to the function is empty. There are two base cases:
When the list is empty -> return None
When the list has one item -> return list[0]
And then the recursive case ... to reduce any other case into the base case.
def recursive_max(arr):
if len(arr) == 0:
return None
elif len(arr) == 1:
return arr[0]
else:
maxItem = recursive_max(arr[1:])
return maxItem if maxItem > arr[0] else arr[0]
Here is my answer, with a one line of code :))
def max_value(n_list):
return n_list[0] if len(n_list) == 1 else max(n_list[0], max_value(n_list[1:]))
def getMaxNumber(numbers):
return 'N.A' if len(numbers) == 0 else max(numbers)
I started learning python today from the tutorial on the official site.
When reading about filter(function, sequence) i thought of making a function that returns if a number is prime to use it with the filter.
notDividedBy = [2,3,4,5,6,7,8,9]
def prime(num):
"""True if num is prime, false otherwise"""
copy = notDividedBy[:]
check = True
if num in copy:
copy.remove(num)
for x in copy:
if num % x == 0:
check = False
break
return check
The above code works in the shell.
My question is: Since i feel like although a solution, it is not the most elegant one, can anyone transform this code to something more python-like?(better structure? less lines?)
I believe it would help me for better understanding of the basics of the language.
The thing is, don't use any imports or anything, just simple staff.
Creating many many copies of lists is not a particularly efficient way of doing things. Instead use the xrange() (Python 2.x) or range() (Python 3) iterator. Here's one (naive) way you could implement a primality test:
from math import sqrt
def isPrime(n):
if n < 2: return False
if n == 2: return True
if not n % 2: return False #test if n is even
#we've already remove all the even numbers, no need to test for 2
#we only need to test up to sqrt(n), because any composite numbers can be
# factored into 2 values, at least one of which is < sqrt(n)
for i in xrange(3, int(sqrt(n)) + 1, 2):
if not n % i:
return False
return True
How about this one:
def is_prime(num):
return not any(num%i == 0 for i in xrange(2,num/2+1))
for i in xrange(10):
print i, is_prime(i)
Explanation
start with:
(num%i==0 for i in xrange(2,num/2+1))
This is a generator expression. I could have made it a list comprehension:
[num%i==0 for i in xrange(2,num/2+1)]
The list comprehension is equivalent to:
ll=[]
for i in xrange(2,num/2+1):
ll.append(num%i==0)
The difference between the generator and the list comprehension is that the generator only gives up it's elements as you iterate over it -- whereas the list comprehension calculates all the values up front. Anyway, from the above code, you can see that the expression generates a sequence of True's and False's. True if the number can be divided by i and False otherwise. If we generate a sequence of all False numbers, we know we have a prime.
The next trick is the any built in function. It basically searches through an iterable and checks if any of the values is True. As soon as it hits a True, it returns True. If it gets to the end of the iterable, it returns False. So, if the entire sequence is False (a prime number) then any will return False, otherwise it returns True. This would be perfect for a not_prime function, but our function is is_prime, so we just need to invert that result using the not operator.
The benefit of using the generator expression is that it is nice and concise, but also that it allows any to return before checking every value which means that as soon as it finds a number that divides num, it returns instead of generating all num/2 numbers.
Anyway, I hope this explanation is helpful. If not, feel free to leave a comment and I'll try to explain better.
One thing off the bat, if you are going to implement prime testing in this fashion, there's no reason to use an auxillary array
def prime(num):
"""True if num is prime, false otherwise"""
check = True
#if num in copy:
# copy.remove(num)
for x in range(2,x-1):
if num % x == 0:
check = False
break
return check
Here's a 2 liner using filter().
def prime(num):
"""True if num is prime, false otherwise"""
if num < 2:
return False
return len(filter(lambda x: num % x == 0, range(2, num))) == 0