So I create a tree in python. I am trying to change some value of every child of the root node. But, every node in my tree is not being hit.
class Node(object):
def __init__(self, value, priority):
self.parent = None
self.children = []
self.value = value
self.priority = priority
def add_child(self, obj):
self.children.insert(obj)
obj.parent = self
def getChildren(self):
return self.children.getAll()
tom = Node("DD",1)
tom.add_child(Node("a",0.3))
tom.add_child (Node("b", 0.6))
tom.getChildren()[0].add_child(Node("c",1))
tom.getChildren()[1].add_child(Node("d",1))
#print(tom.popHighestValue().value)
def getAll(currentNode):
print(currentNode.value)
if(currentNode.getChildren != []):
for sibling in currentNode.getChildren():
sibling.priority = 1
return getAll(sibling)
The tree should look like:
DD
/\
a b
/
c
But only DD->a->c are being hit. I thought the for loop state would be saved and continued after DD -> c was traversed.
The goal is that every node in the tree is hit. And the priority value is set to 1.
A return statement always exits the current function. If you're in a loop when you do this, the rest of the loop is never executed.
If you need to return all the values of the recursive calls, you need to collect them in a list during the loop, then return that list after the loop is done.
But in this case there doesn't seem to be anything you need to return. This function is just for setting an attribute, there's nothing being extracted. So just make the recursive call without returning.
def getAll(currentNode):
print(currentNode.value)
for sibling in currentNode.getChildren():
sibling.priority = 1
getAll(sibling)
BTW, this won't set the priority of the root node, since it only sets the priority of children. If you want to include the root node, it should be:
def getAll(currentNode):
print(currentNode.value)
currentNode.priority = 1
for sibling in currentNode.getChildren():
getAll(sibling)
Also, you shouldn't call getAll() in the getChildren() method. It just return self.children, not self.children.getAll().
If you remove the return before calling getAll() and place it outside the enclosing for loop, that would fix your problem.
In your code, you are unable to process all the children because right after your first iteration you call getAll() with the return statement. So, all the other siblings except first are/will not be explored at every depth.
Related
In my task first I need to make single linked-list from array.
My code:
class Node:
def __init__(self,data):
self.data = data
self.next = next
class Lista:
def __init__(self, lista=None)
self.head = None
def ispis(self):
printval = self.head
while printval .next is not None:
print(printval.next.data)
printval = printval.next
if __name__ == '__main__'
L = Lista ([2, "python", 3, "bill", 4, "java"])
ispis(L)
With function ispis I need to print elements of linked-list. But it says name "ispis" is not defined. Cannot change ispis(L) !
EDIT: removed next from and ispis(self) is moved outside Lista class
while printvla.next is not None:
EDIT2:
It shows that L is empty so thats why it won't print anything. Should I add elements to class Node ?
ispis is a method in a class. But you are calling the function as if it is a normal function outside the class.
Atleast you have created the object correctly. Below would be the correct way of calling the method inside the class.
L.ispis()
This question sounds suspiciously like a homework assignment. If the instructor is trying to teach you how to create linked lists, you need to go back to what you need to do:
A node when set up for the first time only needs the data. Typically the next pointer/value would be set to None (meaning no next member).
Your __init__ method for your Lista class needs to do something with its argument.
I believe if you need to use your ispls function to operate on a class, then the function probably isn't supposed to be a member of Lista.
I think your ispls loop shouldn't be testing its .next member. This would fail if you had a None to begin with. You should be testing the current instance rather than its next. That way, when you move on to the next node, if it's None, it gets out of the loop.
Be careful with the keyword next. I would avoid using it as a class attribute. Also the literal next would just give you the built-in command.
At the bare minimum, you would want to iterate over the lista argument in __init__, creating a Node for each one, saving the previous node for the next operation.
if lista is None:
self.head = None
return
prev = None
for data in lista:
node = Node(data)
if prev is None:
self.head = node
else:
prev.next = node
prev = node
But again, I believe that is what the instructor wanted you to figure out. Hope this helped.
--B
This question already has answers here:
Why does using `arg=None` fix Python's mutable default argument issue?
(5 answers)
Closed 3 years ago.
I want to implement a very simple tree data structure in Python.
I want to make it so that everytime I add a new node and I specify its parent, then it is automatically added to the children attribute of its parent.
I have two different ways to do it, one works and one doesn't but I don't understand why.
class Node():
def __init__(self, value, parent = None, children = []):
self.value = value #This is for us to see the name
self.parent = parent #Parent node
self.children = children #List of child nodes
#Set this Node as a children of its own parent
if not parent == None:
#self.parent.children.append(self) <--- wrong code
self.parent.children = self.parent.children + [self]
def __repr__(self):
return str(self.value)
tree = Node("tree")
branch1 = Node("branch1", parent = tree)
branch2 = Node("branch2", parent = tree)
leaf = Node("leaf", parent = branch1)
Here is what I get with the code as is and what I would get if I replace the last line of __init__ with the commentated line.
print(tree.children)
#[branch1, branch2] <--- expected
#[branch1, branch2, leaf] <--- with wrong code
print(branch1.children)
#[leaf] <--- expected
#[branch1, branch2, leaf] <--- with wrong code
Using the .append method adds the node not only to the list children of its parent but to everybody. Even if I define a new Node("other") completely detached from the others. Why is that?
The problem is in the use of mutable default value:
def __init__(self, value, parent = None, children = []):
The empty list [] gets created only once, when the function is defined, and all invocations share the same list! This is why append to one list of children modifies all of them - because they all are one and the same list object. When you use + to append to the list, you work around the above bug because you re-create the list every time, thus unsharing the children objects.
The correct solution is to replace children=[] with something like:
def __init__(self, value, parent=None, children=None):
if children is None:
children = []
That will guarantee the creation of a new list for children, and then append and + should have the same result.
For example if I wanted to change greater than to less than or equal to I have successfully executed:
def visit_Gt(self, node):
new_node = ast.GtE()
return ast.copy_location(new_node, node)
How would I visit/detect an assignment operation (=) and a function call () and simply delete them? I'm reading through the AST documentation and I can't find a way to visit the assignment or function call classes and then return nothing.
An example of what I'm seeking for assignment operations:
print("Start")
x = 5
print("End")
Becomes:
print("Start")
print("End")
And an example of what I'm seeking for deleting function calls:
print("Start")
my_function_call(Args)
print("End")
Becomes
print("Start")
print("End")
You can use a ast.NodeTransformer() subclass to mutate an existing AST tree:
import ast
class RemoveAssignments(ast.NodeTransformer):
def visit_Assign(self, node):
return None
def visit_AugAssign(self, node):
return None
new_tree = RemoveAssignments().visit(old_tree)
The above class removes None to completely remove the node from the input tree. The Assign and AugAssign nodes contain the whole assignment statement, so the expression producing the result, and the target list (1 or more names to assign the result to).
This means that the above will turn
print('Start!')
foo = 'bar'
foo += 'eggs'
print('Done!')
into
print('Start!')
print('Done!')
If you need to make more fine-grained decisions, look at the child nodes of the assignment, either directly, or by passing the child nodes to self.visit() to have the transformer further call visit_* hooks for them if they exist:
class RemoveFunctionCallAssignments(NodeTransformer):
"""Remove assignments of the form "target = name()", so a single name being called
The target list size plays no role.
"""
def visit_Assign(self, node):
if isinstance(node.value, ast.Call) and isinstance(node.value.func, ast.Name):
return None
return node
Here, we only return None if the value side of the assignment (the expression on the right-hand side) is a Call node that is applied to a straight-forward Name node. Returning the original node object passed in means that it'll not be replaced.
To replace top-level function calls (so those without an assignment or further expressions), look at Expr nodes; these are expression statements, not just expressions that are part of some other construct. If you have a Expr node with a Call, you can remove it:
def visit_Expr(self, node):
# stand-alone call to a single name is to be removed
if isinstance(node.value, ast.Call) and isinstance(node.value.func, ast.Name):
return None
return node
Also see the excellent Green Tree Snakes documentation, which covers working on the AST tree with further examples.
Right now, I have a base 10 to base 2 converter that works, however it always prints none at the end of every conversion.
base_two=0
def binary_recursion(base_ten):
global base_two
if base_ten==0:
print(base_two)
return
c=0
while base_ten//2**c>1:
c+=1
base_two+=10**c
if c==0:
print(base_two)
return
binary_recursion(base_ten-2**c)
I tried returning base_two as opposed to printing it, but that doesn't return a number, it also just returns None. Can anyone help me pinpoint my mistake?
def node(document_info, next_node):
return {'data': document_info, 'next': next_node}
def insert(head, new_document_info):
#insert new document into the linked list head
#returns the head of the modified list
if head is None:
return node(new_document_info, None)
if new_document_info[1] <= head['data'][1]:
return node(new_document_info, head)
head['next'] = insert(head['next'], new_document_info)
return head
Here's a slightly modified way of doing insertion sort, from my answer to you last question. You would start with head = None and then every time you add a print job do head = insert(head, document_info). Or after collecting all of your print jobs do something like
head = None
for document_info in list_queue:
head = insert(head, document_info)
You are not adding new element into queue. Assuming list_queue is a queue.
Queue has put function to add a new element into it.
def make_job():
temp_list=[]
list_queue = Queue()
for line in print_list:
if line[:6]=='submit': #If the command is submit, then the file must be placed in its
a=line.split() #correct spot in the linked list
del(a[0])
list_queue.put(a)#Contains file id, and the time required to print
temp_list.append(list_queue)
organize(list_queue) #Places the file in its correct spot in the linked list
else:
break
The Python queue module has a class called PriorityQueue that does exactly what you're looking for. For your situation, using it would look something like this:
class Job(object):
def __init__(self, name, print_time):
self.name = name
self.print_time = print_time
def __lt__(self, other):
return self.print_time < other.print_time
import queue as _queue # Need to rename the module so it doesn't conflict with your 'queue' function
my_queue = _queue.PriorityQueue()
def make_job():
for line in print_list:
if line[:6]=='submit':
a=line.split()
del(a[0])
new_job=queue(a) # queue(a) now returns a Job, e.g. Job('101', 40), instead of a 2-element list
my_queue.put(new_job)
else:
break
Once my_queue has been constructed, then repeated calls to my_queue.get() will return the Jobs ordered by print_time.
If you want to be able to inspect the contents of the queue without removing elements (get removes the element it returns), you could append the Jobs to a list and call list_queue.sort() after every insertion. If this is a performance concern, you could find the right spot in the list yourself and call list_queue.insert(i, a). Deferring to Python's list.sort has some advantages, though; namely, it's stable.
Lastly, if you don't want to define a new class, you could use sorted or list.sort with a custom sorting function. This takes the place of the __lt__ member I defined for Job.
new_job=queue(a) # queue(a) is your original function, which returns 2-element lists like ['101', 40]
list_queue.append(new_job)
list_queue.sort(key=lambda a,b: return a[1]<b[1])
I need functionality similar to QListIterator such as:
next() - found ofcourse in python
peekNext()
previous()
Tried to look for a Python similar class.
That is the way i handeled it in the end.
A class based on UserList class with hasNext() method for checking if iterating forward is possible and other two for getting next value with no index increment and getting next value with index increment.
Nothing too special.
class BiDirectList(UserList.UserList):
"""
list with peek into next value method with no index increment
"""
def __init__(self, userList):
super(BiDirectList, self).__init__(userList)
self.next = 0
def hasNext(self):
# check if next value exists
try:
if self.data[self.next]: # data represent the list associated with the class object
return True
except IndexError:
return False
def getNext(self):
# gets next value and advance index in one
val = self.data[self.next]
self.next += 1
return val
def peekNext(self):
# gets next value if exists with no index increment
return self.data[self.next]