find self index for nested Python object - python

class Node:
def __init__(self,parent = None):
self.parent = parent
self.children = []
def AddNode(self):
self.children.append(Node(self))
def getIndex(self):
return self.parent.children.index(self)
a = Node()
b = a.AddNode()
print b.getIndex()
In a tree of objects like the above, what's the best way for a child to find out its index within the parent's children? I'm using self.parent.children.index(self), but that seems contorted. Is there a better way?

One nit: this doesn't quite work, because AddNode doesn't return anything.
Other than that what you've done is fine. So long as you're doing on-demand (lazy) retrieval of the index, this is a direct way to do it. If you want something more direct, I suggest that you store the index when the child is linked in AddNode.
class Node:
def __init__(self,parent = None):
self.parent = parent
self.children = []
self.child_index = None
def AddNode(self):
new_child = Node(self)
self.children.append(new_child)
new_child.child_index = self.children.index(new_child)
return new_child
def getIndex(self):
return self.child_index
a = Node()
b = a.AddNode()
c = a.AddNode()
d = a.AddNode()
print d.getIndex()
print c.getIndex()
print b.getIndex()
Output (booooorrriiinnngg):
2
1
0

Related

adding childern to tree stucture and print

I am trying to implement an n-arry tree based on this post :
[here][1]
and I am getting an error when trying to define a function that adds children:
class node(object):
def __init__(self, value, children = []):
self.value = value
self.children = children
def __str__(self, level=0):
ret = "\t"*level+repr(self.value)+"\n"
for child in self.children:
ret += child.__str__(level+1)
return ret
# trying to implement this method si that I can get rid of
# calling root.children[0].children
def add_child(self, obj):
self.children.append(obj)
def __repr__(self):
return '<tree node representation>'
root = node('grandmother')
root.children = [node('daughter'), node('son')]
root.children[0].children = [node('granddaughter'), node('grandson')]
root.children[1].children = [node('granddaughter'), node('grandson')]
root.add_child([node((1)), node(2)]) # error
print (root)
I want to be able to to create a tree and print it.
[1]: Printing a Tree data structure in Python
If you name a method add_child, it should add a child, not children. And if you add children, you should extend the list, not just append the given list on its end.
Working example:
class Node(object):
def __init__(self, value, children=None):
if children is None:
children = []
self.value = value
self.children = children
def __str__(self, level=0):
ret = "\t" * level + repr(self.value) + "\n"
for child in self.children:
ret += child.__str__(level + 1)
return ret
def add_children(self, obj):
self.children.extend(obj)
root = Node('grandmother')
root.children = [Node('daughter'), Node('son')]
root.children[0].children = [Node('granddaughter'), Node('grandson')]
root.children[1].children = [Node('granddaughter'), Node('grandson')]
root.add_children([Node(1), Node(2)])
print(root)
Output:
'grandmother'
'daughter'
'granddaughter'
'grandson'
'son'
'granddaughter'
'grandson'
1
2
You call add_child with an entire list object. Within add_child you use the method list.append which adds the entire list object to the list itself.
Solution 1: call add_child by specifying the nodes directly:
root.add_child(node((1))
root.add_child(node((2))
Solution 2: change the implementation of add_child by using list.extend instead of list.append. The former adds each element within the supplied argument to the list, while the latter adds the entire argument to the list.
def add_child(self, obj):
self.children.extend(obj)

I want to make a linked list by dummy headed But why the code is printing reverse!!. Here is my code

I want to make a linked list by dummy headed circular but I can't understand why the code is printing reverse.
class Node:
def __init__(self, value, next, prev ):
self.data = value
self.next = next
self.prev = prev
class DoublyList:
def __init__(self, c):
self.head = Node(None,None,None) #instance variable
self.head.prev = self.head.next = self.head
for i in c:
store = Node(i, None, None)
store.next = self.head.next
store.prev = self.head
self.head.next = store
store.next.prev = store
def showList(self):
n = self.head.next
while n !=self.head:
print(n.data, end=' ')
n = n.next
a = [10,20,30,40,50,60]
l1 = DoublyList(a)
l1.showList()
Since you want to add each subsequent node after the last node in the list, it should be inserted just before the sentinel (head) node.
I would also suggest the following change to the Node constructor, so that it defaults to making a self-reference when the second and third argument are not provided:
class Node:
def __init__(self, value, nxt=None, prev=None):
self.data = value
self.next = nxt or self
self.prev = prev or self
And make good use of those parameters when you do pass arguments for them:
class DoublyList:
def __init__(self, c):
self.head = Node(None)
for i in c:
store = Node(i, self.head, self.head.prev)
store.prev.next = store.next.prev = store
The following code works:
class DoublyList:
def __init__(self, c):
self.head = Node(None,None,None) #instance variable
self.head.prev = self.head.next = self.head
for i in c:
store = Node(i, None, None)
store.prev = self.head.prev
store.next = self.head
self.head.prev = store
store.prev.next = store
print(store," ",store.prev)
if store.prev==self.head:
self.head.next=store #first node
There were 2 problems with your original code:
1:
You switched the prev and the next attribute. This is an easy fix: just change all `prev` attributes into `next` and vice versa.
2:
When executing the code after that, you might have noticed that there's nothing printed at all. This happens because your `self.head.next` remains setted to `self.head`, making your program not even start the while loop. To fix it, you've to find the first node in your for loop, and set `self.head.next` to it

What does assigning self to a variable in Python Class mean?

While I was learning Tree data structure in python, I came across this code:
class TreeNode:
def __init__(self, data):
self.data = data
self.children = []
self.parent = None
def get_level(self):
level = 0
p = self.parent
while p:
level += 1
p = p.parent
return level
def print_tree(self):
spaces = ' ' * self.get_level() * 3
prefix = spaces + "|__" if self.parent else ""
print(prefix + self.data)
if self.children:
for child in self.children:
child.print_tree()
def add_child(self, child):
child.parent = self
self.children.append(child)
def build_product_tree():
root = TreeNode("Electronics")
laptop = TreeNode("Laptop")
laptop.add_child(TreeNode("Mac"))
laptop.add_child(TreeNode("Surface"))
laptop.add_child(TreeNode("Thinkpad"))
cellphone = TreeNode("Cell Phone")
cellphone.add_child(TreeNode("iPhone"))
cellphone.add_child(TreeNode("Google Pixel"))
cellphone.add_child(TreeNode("Vivo"))
tv = TreeNode("TV")
tv.add_child(TreeNode("Samsung"))
tv.add_child(TreeNode("LG"))
root.add_child(laptop)
root.add_child(cellphone)
root.add_child(tv)
root.print_tree()
if __name__ == '__main__':
build_product_tree()
It was a tutorial from Codebasics: https://www.youtube.com/watch?v=4r_XR9fUPhQ&list=PLeo1K3hjS3uu_n_a__MI_KktGTLYopZ12&index=9
Now my question is why in the 25th line there is child.parent = self what does it mean or why should I have to do that.
self references the current instance. This line of code will tell the child that it's parent is the current instance.

Sometimes None is printed - and sometimes it doesn't, can't get why?

I got this school assignment, here is my code:
class Doubly_linked_node():
def __init__(self, val):
self.value = val
self.next = None
self.prev = None
def __repr__(self):
return str(self.value)
class Deque():
def __init__(self):
self.header = Doubly_linked_node(None)
self.tailer = self.header
self.length = 0
def __repr__(self):
string = str(self.header.value)
index = self.header
while not (index.next is None):
string+=" " + str(index.next.value)
index = index.next
return string
def head_insert(self, item):
new = Doubly_linked_node(item)
new.next=self.header
self.header.prev=new
self.header=new
self.length+=1
if self.tailer.value==None:
self.tailer = self.header
def tail_insert(self, item):
new = Doubly_linked_node(item)
new.prev=self.tailer
self.tailer.next=new
self.tailer=new
self.length+=1
if self.header.value==None:
self.header = self.tailer
it builds a stack, allowing you to add and remove items from the head or tail (I didn't include all the code only the important stuff).
When I initiate an object, if I return self.next it prints None, but if I return self.prev, it prints nothing, just skips, I don't understand why since they are both defined exactly the same as you see, and if I insert only head several times for example for i in range(1,5): D.head_insert(i) and then I print D it prints 5 4 3 2 1 None but if I do tail insert for example for i in range(1,5): D.tail_insert(i) and print D it prints 1 2 3 4 5"as it should without the None. Why is that?
I have included an image:
Keep in mind that you create a Deque which is not empty. You're initializing it with a Node with value None
You're interchanging the value and the Node object. When you're checking if self.tailer.value==None: it's probably not what you're meaning
Following to point 2 is a special handling for the empty Deque, where header and tailer is None
Here is what I have in mind, if I would implement the Deque. I'm slightly changed the return value of __repr__.
class Deque():
def __init__(self):
self.header = None
self.tailer = None
self.length = 0
def __repr__(self):
if self.header is None:
return 'Deque<>'
string = str(self.header.value)
index = self.header.next
while index!=None:
string+=" " + str(index.value)
index = index.next
return 'Deque<'+string+'>'
def head_insert(self, item):
new = Doubly_linked_node(item)
new.next=self.header
if self.length==0:
self.tailer=new
else:
self.header.prev=new
self.header=new
self.length+=1
def tail_insert(self, item):
new = Doubly_linked_node(item)
new.prev=self.tailer
if self.length==0:
self.header=new
else:
self.tailer.next=new
self.tailer=new
self.length+=1
Following Günthers advice, I have modified the __repr__ to this:
def __repr__(self):
string = str(self.header.value)
index = self.header
while not (str(index.next) == "None"):
string += (" " + str(index.next.value))
index = index.next
return string
that did solve the problem, but it is the ugliest solution I have ever seen.
does anyone know a better way?
Following to the question of a better __repr__ method here my proposal. Extend the Deque class with an __iter__ method. So you can iterate over the Deque which is nice to have, e.g.:
for item in D:
print item
Based on that the __repr__ method is easy. Here is the whole change:
def __repr__(self):
return 'Deque<'+' '.join([str(item.value) for item in self])+'>'
def __iter__(self):
index=self.header
while index is not None:
yield index.value
index=index.next

Using self.xxxx as a default parameter - Python

I'm trying to simplify one of my homework problems and make the code a little better. What I'm working with is a binary search tree. Right now I have a function in my Tree() class that finds all the elements and puts them into a list.
tree = Tree()
#insert a bunch of items into tree
then I use my makeList() function to take all the nodes from the tree and puts them in a list.
To call the makeList() function, I do tree.makeList(tree.root). To me this seems a little repetitive. I'm already calling the tree object with tree.so the tree.root is just a waste of a little typing.
Right now the makeList function is:
def makeList(self, aNode):
if aNode is None:
return []
return [aNode.data] + self.makeList(aNode.lChild) + self.makeList(aNode.rChild)
I would like to make the aNode input a default parameter such as aNode = self.root (which does not work) that way I could run the function with this, tree.makeList().
First question is, why doesn't that work?
Second question is, is there a way that it can work? As you can see the makeList() function is recursive so I cannot define anything at the beginning of the function or I get an infinite loop.
EDIT
Here is all the code as requested:
class Node(object):
def __init__(self, data):
self.data = data
self.lChild = None
self.rChild = None
class Tree(object):
def __init__(self):
self.root = None
def __str__(self):
current = self.root
def isEmpty(self):
if self.root == None:
return True
else:
return False
def insert (self, item):
newNode = Node (item)
current = self.root
parent = self.root
if self.root == None:
self.root = newNode
else:
while current != None:
parent = current
if item < current.data:
current = current.lChild
else:
current = current.rChild
if item < parent.data:
parent.lChild = newNode
else:
parent.rChild = newNode
def inOrder(self, aNode):
if aNode != None:
self.inOrder(aNode.lChild)
print aNode.data
self.inOrder(aNode.rChild)
def makeList(self, aNode):
if aNode is None:
return []
return [aNode.data] + self.makeList(aNode.lChild) + self.makeList(aNode.rChild)
def isSimilar(self, n, m):
nList = self.makeList(n.root)
mList = self.makeList(m.root)
print mList == nList
larsmans answered your first question
For your second question, can you simply look before you leap to avoid recursion?
def makeList(self, aNode=None):
if aNode is None:
aNode = self.root
treeaslist = [aNode.data]
if aNode.lChild:
treeaslist.extend(self.makeList(aNode.lChild))
if aNode.rChild:
treeaslist.extend(self.makeList(aNode.rChild))
return treeaslist
It doesn't work because default arguments are evaluated at function definition time, not at call time:
def f(lst = []):
lst.append(1)
return lst
print(f()) # prints [1]
print(f()) # prints [1, 1]
The common strategy is to use a None default parameter. If None is a valid value, use a singleton sentinel:
NOTHING = object()
def f(arg = NOTHING):
if arg is NOTHING:
# no argument
# etc.
If you want to treat None as a valid argument, you could use a **kwarg parameter.
def function(arg1, arg2, **kwargs):
kwargs.setdefault('arg3', default)
arg3 = kwargs['arg3']
# Continue with function
function("amazing", "fantastic") # uses default
function("foo", "bar", arg3=None) # Not default, but None
function("hello", "world", arg3="!!!")
I have also seen ... or some other singleton be used like this.
def function(arg1, arg2=...):
if arg2 is ...:
arg2 = default

Categories