Iteration to Recurssion - python-3.x

so myListToPyList(lst): takes lst, a MyList object and returns a Python list containing the same data
def myListToPyList(lst):
return myListToPyListRec(lst.head)
here's my helper function:
def myListToPyListRec(node):
if node == None:
return
else:
st1 = []
st1.append(node.data)
myListToPyListRec(node.next)
return st1
it's not working correctly.
Now here is my iterative solution that works correctly:
def myListToPyList(lst):
"""
Takes a list and returns a python list containing
the same data
param; lst
return; list
"""
st1 = []
curr = lst.head
while curr != None:
st1.append(curr.data)
curr = curr.next
return st1

Your current recursive code doesn't work because each time it gets called, it creates a new empty list, adds a single value to the list, then recurses (without passing the list along). This means that when the last item in the link list is being processed, the call stack will have N one-element Python lists (where N is the number of list nodes).
Instead, you should create the list just once, in your non-recursive wrapper function. Then pass it along through all of the recursion:
def myListToPyList(lst):
result_list = [] # create just one Python list object
myListToPyListRec(lst.head, result_list) # pass it to the recursive function
return result_list # return it after it has been filled
def myListToPyListRec(node, lst):
if node is not None # the base case is to do nothing (tested in reverse)
lst.append(node.data) # if node exists, append its data to lst
myListToPyListRec(node.next, lst) # then recurse on the next node
Because Python lists are mutable, we don't need to return anything in our recursive calls (None will be returned by default, but we ignore that). The list referred to by result_list in myListToPyList is the same object referred to by lst in each of the recursive calls to myListToPyListRec. As long as the recursive function mutates the object in place (e.g. with append) rather than rebinding it, they'll all see the same thing.
Note that recursion is going to be less eficient in Python than iteration, since function calls have more overhead than just updating a couple variables.

A while loop is equivalent to tail recursion, and vice versa. (One reason Python does not have automatic tail-call elimination is that the 'vice versa' part is rather easy.) The tail recursion requires that you add an accumulator parameter to be returned in the base case. Although I do not have a linked list for testing, I believe the following should work. (If not, this is close.) Python's default arguments make the helper either easier or unnecessary.
def myListToPyListRec(node, py_list=[]):
if node
py_list.append(node.data)
return myListToPyListRec(node.next, py_list)
else:
return py_list

Related

Python recursive function to create generic tree [duplicate]

This question already has answers here:
Why does my recursive function return None?
(4 answers)
Closed 7 months ago.
I'm trying to create a tree with n children for each node.
Problem is, when I try to implement this using a recursive function, I ends up with multiple recursive calls so I can't have a single return statement, hence having None as a final result.
Here is my piece of code :
def recursive_func(tree, n):
if n == 0:
return tree
else:
permutations = get_permutations()
for permutation in permutations:
child_tree = recursive_func(Tree(permutation), n-1)
tree.addChild(child_tree)
get_permutations() gives a list of child trees to create. I also have a Tree class with a node value and a list of children.
Here is the Tree class:
class Tree:
def __init__(self, result):
self.node = node
self.children = []
def addChild(self, tree):
self.children.append(tree)
This is probably a rookie error in the design of my problem, but I would be glad to get some help.
TLDR: Since you use the result of recursive_func, it should always return its tree.
The recursive_func has three important points for this problem:
def recursive_func(tree, n):
if n == 0:
return tree # 1.
else:
permutations = get_permutations()
for permutation in permutations:
child_tree = recursive_func(Tree(permutation), n-1) # 2.
tree.addChild(child_tree)
# 3.
Now, 1. defines that the function sometimes returns a Tree. This matches 2. which always expects the function to return a Tree. However, both conflict with 3., which implicitly returns None when the second branch is done.
Since the first branch is empty aside from the return, both 1. and 3. can be collapsed to one path that always returns a Tree.
def recursive_func(tree, n):
if n > 0:
permutations = get_permutations()
for permutation in permutations:
child_tree = recursive_func(Tree(permutation), n-1)
tree.addChild(child_tree)
return tree

Reverse a singly linked list

Reverse a singly linked list.
Example:
Input: 1->2->3->4->5->NULL
Output: 5->4->3->2->1->NULL
Here's what I saw online:
class Solution:
def reverseList(self, head):
def reverse(prev, cur):
if cur:
reverse(cur, cur.next)
cur.next = prev
else:
nonlocal head
head = prev
reverse(None, head)
return head
But I didn't get the process how it works after the if cur.
For example the test case is [1,2,3,4,5].
input None, 1 into the reverse function
cur exist, run reverse function with 1, 2
...
cur exist, run reverse function with 4, 5
cur does not exist, (then what???)
BTW why does listNode even exist? It is not as easy as others like list array or dictionary. When should i use it?
There's no efficient way to do this. The only way without interacting with the list beforehand, is an algorithm of a complexity of O(n * n), where you repeatedly go through the linked list, find last element and remove it, while adding it to a new linked list, until the first list is completely empty. If you wanted to preserve that list, you'd have to recreate that list during the reversing or simply copy it beforehand, not fun at all. This is what example you posted does.
def reverse(prev, cur):
if cur: # this should actually be if cur is not None:
reverse(cur, cur.next) # call same method on next node
cur.next = prev # when we are back from recursion hell, set previous one as next one, because we are reversing
else: # we finally reached the end
nonlocal head # excuse me, this is in a class but you wrap in multiple functions and use nonlocal??? Where did you even dig out this thing from?
head = prev # head now becomes the previous node, because this node is None, or, end of the list
If you just want to learn about them, then this algorithm is perfectly fine, in any other case, you should at least upgrade to doubly linked list, you'll use insignificant amount of memory to speed up reversal a lot.
If you create your own doubly linked list, reversing could be as fast as swapping end and start "pointers", if you write it in a way where every node has two references, left and right in a list, such as neighbours = [left, right], your linked list could store a value called advance direction, which would be either 0 or 1, meaning that you could reverse entire list from start to end while going to left to right to end to start while going right to left by merely swapping start with end and changing "advance value" from 1 to 0. The advance value would be wrapped in a method like next(), which would look something like this:
def next(self):
if self.current is None:
return None # could be return self.current or even just "return", this is Python
self.current = self.current.neighbours[self.advance_value]
return self.current
When advance_value is 0, it goes left, when advance_value is 1, it goes right through the list, all elements stay in their place, but to whoever is accessing it, it looks like it's reversed.

python3 list creation from class makes a global list rather than a series iterated ones

So here is the problem I am having. I am trying to iterate the makeAThing class, and then create a list for the iteration using the makeAList class. Instead of making seperate lists for each iteration of makeAThing, it is making one big global list and adding the different values to it. Is there something I am missing/don't know yet, or is this just how python behaves?
class ListMaker(object):
def __init__(self,bigList = []):
self.bigList = bigList
class makeAThing(object):
def __init__(self,name = 0, aList = []):
self.name = name
self.aList = aList
def makeAList(self):
self.aList = ListMaker()
k = []
x = 0
while x < 3:
k.append(makeAThing())
k[x].name = x
k[x].makeAList()
k[x].aList.bigList.append(x)
x += 1
for e in k:
print(e.name, e.aList.bigList)
output:
0 [0, 1, 2]
1 [0, 1, 2]
2 [0, 1, 2]
the output I am trying to achieve:
0 [0]
1 [1]
2 [2]
After which I want to be able to edit the individual lists and keep them assigned to their iterations
Your init functions are using mutable default arguments.
From the Python documentation:
Default parameter values are evaluated from left to right when the
function definition is executed. This means that the expression is
evaluated once, when the function is defined, and that the same
“pre-computed” value is used for each call. This is especially
important to understand when a default parameter is a mutable object,
such as a list or a dictionary: if the function modifies the object
(e.g. by appending an item to a list), the default value is in effect
modified. This is generally not what was intended. A way around this
is to use None as the default, and explicitly test for it in the body
of the function, e.g.:
def whats_on_the_telly(penguin=None):
if penguin is None:
penguin = []
penguin.append("property of the zoo")
return penguin
In your code, the default argument bigList = [] is evaluated once - when the function is defined - the empty list is created once. Every time the function is called, the same list is used - even though it is no longer empty.
The default argument aList = [] has the same problem, but you immediately overwrite self.aList with a call to makeAList, so it doesn't cause any problems.
To verify this with your code, try the following after your code executes:
print(k[0].aList.bigList is k[1].aList.bigList)
The objects are the same.
There are instances where this behavior can be useful (Memoization comes to mind - although there are other/better ways of doing that). Generally, avoid mutable default arguments. The empty string is fine (and frequently used) because strings are immutable. For lists, dictionaries and the sort, you'll have to add a bit of logic inside the function.

Python: Default list in function

From the Summerfield's Programming in Python3:
it says as follows:
when default values are given, they are created at the time the def statement is executed, not when the function is called.
But my question is for the following example:
def append_if_even(x, lst =None):
lst = [] if lst is None else lst
if x % 2 ==0:
lst.append(x)
return lst
As the first time definition executed, lst is point to None
But after the function call append_if_even(2),
Shouldn't lst point to [2], since after lst.append(x) lst not point to None anymore ?
Why the next execution still make lst point to none?
What really happen inside this function call append_if_even(2)?
Shouldn't lst point to [2], since after lst.append(x) lst not point to None anymore? Why the next execution still make lst point to none?
That is exactly what you prevent by using the lst=None, lst = [] if lst is None else lst construction. While the default arguments for the function are evaluated only once at compile time, the code within the function is evaluated each time the function is executed. So each time you execute the function without passing a value for lst, it will start with the default value of None and then immediately be replaced by a new empty list when the first line of the function is executed.
If you instead were to define the function like this:
def append_if_even(x, lst=[]):
if x % 2 ==0:
lst.append(x)
return lst
Then it would act as you describe. The default value for lst will be the same list (initially empty) for every run of the function, and each even number passed to the function will be added to one growing list.
For more information, see "Least Astonishment" and the Mutable Default Argument.

using recursion to eliminate duplicates

i'm just starting to learn how recursion works and i keep getting stuck on what i think should be a simple question. I need to create a function using recursion that takes a list and returns a new list with only 1 of each value within the original list.
Example:
original_list = [1,1,2,3,3,4,5]
returned_list = [1,2,3,4,5]
what i have tried:
def recursion(list1):
new_list = []
if list1 == []:
new_list = []
else:
if list1[0] not in list1[1:]:
new_list = new_list.append(list1[0]) + recursion (list1[1:])
else:
new_list = recursion (list1[1:])
return new_list
You're not passing new_list as a parameter to the recursive function; therefore, each level of the recursion is unaware of the results you have gathered so far, and the result of the recursion is only the result of the first level.
(I'm refraining from posting the corrected code since you would presumably like to fix it yourself, and thereby learn more - let me know if you need more hints.)

Resources