python tail recursive function doesn't return - python

I have a function that modifies a list, however it doesn't return anything. It is a long function but to give an example, the following has the same problem. Why is it not returning anything?
def inventedfunction(list1):
list2=list1[:-1]
if len(list2)!=1:
inventedfunction(list2)
else:
return list2

Replace inventedfunction(list2) with return inventedfunction(list2). If you just call it without the return statement, the result is thrown out.
Working code:
def inventedfunction(list1):
list2=list1[:-1]
if len(list2)!=1:
return inventedfunction(list2)
else:
return list2

You didn't say what the function is supposed to do, so I am assuming that "inventedfunction" means "inverted function". Even if this is not correct, the idea is the same. If this is not the case or you don't understand then post back with more info.
You don't catch any of the returns, and don't return anything (None) if len(list2) != 1. You also would have to create a 2nd list to hold the numbers removed from the list sent to the function, and return the updated list as well according to way your code is structured.
def inventedfunction(list1, new_list=[]):
## at the least add print statements so you know what is happening
print new_list, "----->", list1
list2=list1[:-1]
new_list.append(list1[-1]) ## append item removed from list1 --> list2
if len(list2):
new_list, list2=inventedfunction(list2)
return new_list, list2 ## both updated lists returned
print inventedfunction([1, 2, 3, 4, 5])

Related

Why does a call stack differs when returning or storing

I am following a DP&recursion course with JS as the teaching language,
but I encountered some differences with Python..
When returning the call stack, everything goes as it should,
meaning the values in the stack are returning as a whole array:
(the following problem is about finding a combination of elements in the array that sums to totalsum)
def best_sum(totalsum, arr):
if totalsum == 0:
return []
if totalsum < 0:
return None
for num in arr:
remainder = totalsum - num
results = best_sum(remainder, arr)
if results is not None:
return [*results, num]
return None
print(best_sum(7, [2,3,4]))
The output here is:
[3, 2, 2]
But, when I try to save the call stack to an array, I only get 1 item per line:
if results is not None:
comb = [*results, num]
print(comb)
Output:
[3]
[2]
[2]
My answer is.. is there a way to wait for the call stack to finish, before printing the results?
Because I would like to use that array "comb" to do further coding, but I can't since it fills completely only when returned..
I think I misinterpreted something about how a call stack works in Python :)
But, when I try to save the call stack to an array, I only get 1 item per line:
You changed more than only that. You also removed the return statement. So now the for loop is not interrupted, and the function will now return None... a different return value than intended.
That you only get to print lists with one item, is because the base case of your code is still executed correctly, as it returns []. And [*results, num] is therefor equal to [num]. But that is as far as it goes as now your function can only return [] or None, nothing else. This is why you only see lists with one element in your output.
Once you reinstate that return (like return comb), it will work better. The logic of if results is not None depends on those return statements. Printing is not a replacement for a return value when the caller is going to check the return value like it does with that if.

List not returning the proper values as an output

I am trying to write a small function (as an exercise). This function takes a list of values and returns the values that are odd numbers. I have gotten the function to give me the right answer with the print() function, but I am not able to do the same with a return statement.
def odd_nr(list1):
i = 0
for list1[i] in list1:
if list1[i] % 2 != 0:
print(list1[i])
i += 1
return list1
odd_nr([1,2,3,4,5,6])
The output is:
1
3
5
[1, 3, 5, 6, 5, 6]
I am not able to figure out why the return statement gives this output. I tried different indentations, I tried different variants of the return statement, but I just can't seem to get it to work.
What am I doing wrong?
try:
def odd_nr(list1):
results = []
for number in list1:
if number % 2 != 0:
print(number)
results.append(number)
return results
odd_nr([1,2,3,4,5,6])
Further Explanation:
Any function can take something and return something. This something can also be nothing, None.
Your function takes a list, and returns a list, but it is returning the same list that it is taking in.
The print statement is not a return value. Which means a print is not something that the function returns, it is a side-effect, a side door, for us humans to see, mostly.
To return a list of only odd numbers, you need to collect them in another list as you iterate through your original input list.
Then once you are done, return the list that has collected all the odd numbers. Hope this helps.
I also updated your code a bit, for list1[i] in list1, even though it works, it is hard to understand and it does so for the wrong reasons, see below. You can simply do for number in list1 and also not worry about incrementing any counters(i in your case).
Explanation on why for list1[i] in list works:
This is interesting. By choosing list1[i] as the current iteratee, we will be mutating our list while iterating; it is lucky that each iteratee is equal, in value to the list element it is mutating. Here is an example to illustrate what is happening. It is easy to see when we do not update i:
list1= [1,2,3,4]
i=0
for list1[i] in list1:
print(list1[i])
print(list1)
Output:
1
2
3
4
[4, 2, 3, 4]
You just need to return list1[:i] instead of returning the whole list1. Demo with that:
>>> odd_nr([1,2,3,4,5,6])
1
3
5
[1, 3, 5]
With your unusual but correct for list1[i] in list1 and the according update of i, you're moving all the odd numbers to the front of the list and counting them with i. All that's left to do is to only return that front portion.
Alternatively, delete the unwanted back portion with del list1[i:] before you do return list1.

Fibonacci series by recursive function in Python

Hello I am trying to generate Fibonacci series by using a recursive function in python.
Here is my code
def fibolist(n):
list1 = [1, 1]
if n in (1,2) :
return list1
else:
fibolist(n-1).append(sum(fibolist(n-1)[n-3:]))
return list1
but when I enter any number as an argument, the result is [1, 1]
Could you please help me?!
You start with
list1 = [1, 1]
You never change that value, and then you return it to the calling routine.
Each invocation of fibolist has a local variable named list1; appending to one does not change the list1 value in the calling program. You need to explicitly do that. Try
else:
return fibolist(n-1) + [sum(fibolist(n-1)[n-3:])]
Just to fix your code:
def fibolist(n):
if n in (0,1) :
return [1,1]
else:
return fibolist(n-1)+[sum(fibolist(n-1)[n-2:])]
Few notes:
lists in python have starting index=0, so it's better start with it (unless you want to put start return to [0,1,1] for n in (1,2)).
Also - as already mentioned you shouldn't return local variable, which you preassign in each go.
Your code is not updating the list1 variable that it returns upon coming back from the recursion. Doing fibolist(n-1).append(...) updates the list returned by the next level but that is a separate list so list1 is not affected.
You could also make your function much simpler by making it pass the last two values to itself:
def fibo(n,a=1,b=1): return [a] if n==1 else [a] + fibo(n-1,b,a+b)
BTW, the modern interpretation of the fibonacci sequence starts at 0,1 not 1,1 so the above signature should be def fibo(n,a=0,b=1).
Output:
print(fibo(5))
#[1, 1, 2, 3, 5]

This works BUT WHY?

I'm learing Python on codecademy and came across this solution for a function that's meant to remove duplicates from a list of numbers:
x = [1, 1, 2, 2]
def remove_duplicates(x):
p = []
for i in x:
if i != i:
p.append(i)
return i
I ran this in pycharm with some print statements and just got an empty list. I'm only curious because when I do this in my head, it makes no sense, but codecademy accepts this as an answer. Is it just a fluke? Or is this on a level I don't understand yet?
You are correct: it doesn't make any sense. First, it creates a list called p that gets each item that is not equal to itself. The only object that I know of that is not equal to itself is NaN, but you don't have any of those, so p is just an empty list. Defining p is useless, however, because it isn't even returned. What is returned is i, which is assigned to each item in the last, so it is the last item in the list by the end of the function. In short, that function is equivalent to this:
def remove_duplicates(x):
return x[-1]
I haven't heard what the function is supposed to return, but perhaps it is supposed to return the number of non-duplicate items. If it is, it "works" just because the last item in the list happens to be the number of non-duplicate items.
Take a look to this snippet to see the pythonic way to remove duplicated (good_result) and also to understand why your code doesn't make any sense:
x = [1, 1, 2, 2]
def remove_duplicates(x):
p = []
for i in x:
if i != i:
p.append(i)
return i
good_result = list(set(x))
print good_result
print remove_duplicates(x)
As you can see, your function is not returning the filtered list without duplicate values, it's just returning the last element of the list (index=-1). So codeacademy shouldn't accept that snippet as a valid answer to the question how to remove duplicateds from a list for sure.
Now, if we assume what codeacademy was really asking is for the number of unique values from a list, then is a casuality your broken code gives the right answer, which is the same as len(good_result). It worked just by luck just to say, it doesn't mean your code is correct :)
your code just returns the last element of the number, that is same as
return x[-1]
It doesn't return a list.
I think you need to check the question that they may be asking like,
a)function to return one of the duplicating element in a list.
b)function to return the no of duplicating elements in a list.
for the above two questions your answer is 2, by luck the answer is correct.

What happens when returning a reversed list like this

I used this code to return a list say [1,2,3,4]
return (list.reverse())
But it simply wont return the correct result. I had to use
list.reverse()
return list
why is this happening? and when I break up my issue and do
list1 = list.reverse()
in console and print list1, it simply prints "list1"
p.s:- I am a beginner and still learning python.
list.reverse method doesn't return anything. It works over the elements on the list to which is applied (modifying the list). Hence, returning its result will return None. Here's the prof:
>>>[].reverse() == None
True
If you're trying to return a new list with element in reverse order, this is how you do it:
return list[::-1]
This is called slicing in Python and it's used to work with collections.
A small note about returning none: These methods don't actually return None. They don't return any value. But the result of evaluating a function that doesn't return any values is actually None in Python.
Hope this helps!
It's because list.reverse() method reverses list in-place - it doesn't return the reversed list. See the docs.
Use reversed:
return reversed(list)
Generally if you're returning the list reversed, the faster solution is
list.reverse()
return list
You could do
return reversed(list)
but that's generally slower and uses more memory, because it needs to create a new object.
The reason list.reverse() doesn't return the object for convenience is to remind you that it modifies the original list.

Categories

Resources