Parsing a tree using python - python

I have to make a program that parses a tree represented using a set parenthesis and numbers. So each parenthesis represent node in a tree and the program is supposed to print out all the children nodes for each parent node. The python code is as follows:
class context(object):
def __init__(self, label=None, parent=None, children=[]):
self.label = label
self.parent = parent
self.children = []
self.list = []
def make_tree(self, tree):
stack = []
index = 0
while index < len(tree):
if tree[index] is '(':
if self.label is None:
self.label = tree[index+1]
index = index+1
else:
if len(stack) == 0:
stack.append(context(tree[index+1], self.label))
index = index+1
else:
stack.append(context(tree[index+1], stack[len(stack)-1].label))
index = index+1
elif tree[index] is ')':
if len(stack) == 1:
self.children.append(stack.pop())
return
else:
stack[len(stack)-2].children.append(stack.pop())
index = index+1
def traverse(self, size, obj):
if self.label is None or size == 0:
return []
temp_list = []
temp = []
dic = {}
tt = [children.label for children in obj.children]
dic[obj.label] = tt
temp.append(dic)
for child in obj.children:
temp_list = child.traverse(len(child.children), child)
print temp
return temp + temp_list
line = '( Root ( 1 ( 2 ) ( 3 ( 4 ) ( 5 ) ) ( 6 ( 7 ) ( 8 ( 9 ) ) ) ) ) '.split()
test = context()
test.make_tree(line)
final = test.traverse(len(test.children), test)
The result have to be this.
If I print out the list in the make_tree function, I get correct result... But the final result is not correct. In this case, I am missing {'3':['4','5']}
Any comment??

I just looked at some of your code. It didn't have much time so I couldn't have really debugged it way more but you can also implement by having tmpList in the way belong and basically keep updating at every point. Alko's solution works as well, but this might be a bit more clear.
def traverse(self, size, obj, tmpList):
if self.label is None or size == 0:
return []
dic = {}
tt = [children.label for children in obj.children]
dic[obj.label] = tt
tmpList.append(dic)
for child in obj.children:
child.traverse(len(child.children), child, tmpList)
return tmpList
You call this by:
final = test.traverse(len(test.children), test, [])

You overwrite child results with assignment to temp_list, you probably want instead do:
for child in obj.children:
temp_list += child.traverse(len(child.children), child)

Related

Bidirectional BFS in Python Implementation

I am implementing a bidirectional BFS for a 2d maze problem in Python 3.7.3.
Firstly, here is how I create the maze:
for row in range(dim):
# Add an empty array that will hold each cell
# in this row
grid.append([])
for column in range(dim):
grid[row].append(np.random.binomial(1, 0.2, 1)) # Append a cell
if (row == column == dim - 1):
grid[row][column] = 0
grid[0][0] = 0
Now, in order to facilitate the bidirectional BFS, I defined a junct class which is essentially a node which stores both a parent junct from the starting direction and a parent junct from the goal direction.
class junct():
def __init__(self, row, column, parent_S, parent_G):
self.row = row
self.column = column
self.parent_S = parent_S
self.parent_G = parent_G
def __eq__(self, other):
return (self.row == other.row and self.column == other.column)
Here is my bidirectional bfs function. It is part of an Agent class which has not given me any issues so far. I want this function to return a list of tuples (row, column) of all the nodes in the path from the start to the goal.
def bidirectional_bfs(self):
def get_value(maze, a, b):
return maze[a][b]
def is_out_of_bounds(a, b, d):
return (a < 0 or a >= dim) or (b < 0 or b >= d)
grid = self.grid
dim = len(grid)
Q_start = []
Q_goal = []
visited = []
start = junct(0, 0, None, None)
goal = junct(dim-1, dim-1, None, None)
Q_start.append(start)
Q_goal.append(goal)
visited.append(start)
visited.append(goal)
#beginning loop
while (len(Q_start) > 0) and (len(Q_goal) > 0):
#initializations
current_S = Q_start[0]
current_G = Q_goal[0]
row_S = current_S.row
column_S = current_S.column
row_G = current_G.row
column_G = current_G.column
#some mechanics
if len(Q_start) > 0:
Q_start.pop(0)
if len(Q_goal) > 0:
Q_goal.pop(0)
#in case the current node from starting is in the goal Queue
if (current_S in Q_goal):
#forming the path back to G
current = current_S
path_S = [current]
while current.parent_S is not None:
path_S.append(current.parent_S)
current = current.parent_S
path_S = [(item.row, item.column) for item in path_S]
print(path_S)
#in case the current node from goal is in the start Queue
if (current_G in Q_start):
#forming the path back to S
current = current_G
path_G = [currrent]
while current.parent_S is not None:
path_G.append(current.parent_G)
current = current.parent_G
path_G = [(item.row, item.column) for item in path_G]
print(path_G)
if (current_S in Q_goal) and (current_G in Q_start):
path = [item for item in path_G for item in path_S]
print(path)
return path
#enqueueing children from the start direction
children_S = [junct(row_S+1, column_S, current_S, None), junct(row_S-1, column_S, current_S, None), junct(row_S, column_S+1, current_S, None), junct(row_S, column_S-1, current_S, None)]
for child in children_S:
if not is_out_of_bounds(child.row, child.column, dim):
if child not in visited:
if get_value(grid, child.row, child.column) == 0:
Q_start.append(child)
visited.append(child)
#enqueueing childen from the goal direction
#enqueueing children from the start direction
children_G = [junct(row_G+1, column_G, None, current_G), junct(row_G-1, column_G, None, current_G), junct(row_G, column_G+1, None, current_G), junct(row_G, column_G-1, None, current_G)]
for child in children_S:
if not is_out_of_bounds(child.row, child.column, dim):
if child not in visited:
if get_value(grid, child.row, child.column) == 0:
Q_goal.append(child)
visited.append(child)
return []
print("No path")
Where am I going wrong in my code? What needs to be changed in order to return the path?

Add list as child of tree with python 3

I have looked at many very similar questions and cannot figure it out so:
I have a string like this:
{121{12}12{211}2}
I want to read the string into a tree like this:
I am confused as how to tell python to add a whole list as a child node?
I would also like to know how to change the current node to the parent of the old current node?
Here is my code so far:
class Node:
def __init__(self,val):
self.value = val
self.children = []
#init Node class so we can pass in values as nodes and set children to empty list
def add_child(self, obj):
self.children.append(obj)
s=[]
for i in filedata:
if i == leftbrace:
n = Node(i)
#create new child of current node
s = []
#reset list s to blank
if i == rightbrace:
n.add_child(s)
#add list s to current node
#make parent of current node the new current node
else:
s.append(i)
#add i to list s
for c in n.children:
print (c.data)
To make something like this work, it is easiest if you use recursion. Here is one way that this can be done.
Code:
class Node:
def __init__(self, stream):
val = []
children = []
while True:
try:
# get the next character from the stream
ch = next(stream)
# if this is an open brace, then recurse to a child
if ch == '{':
children.append(Node(stream))
# if this is a close brace, we are done on this level
elif ch == '}':
break
# otherwise add this character to our value
else:
val.append(ch)
# stream is empty, we are done
except StopIteration:
break
self.value = ''.join(val)
self.children = children
#classmethod
def from_string(cls, string):
stream = iter(string)
tree_top = Node(stream)
# assert that the string started with '{' and was one top node
assert len(tree_top.children) == 1 and tree_top.value == ''
return tree_top.children[0]
def __str__(self):
return self.value
def __repr__(self):
return "Node('%s', <%d children>)" % (
self.value, len(self.children))
def tree_string(self, level=0):
yield '-' + " " * level + str(self)
for child in self.children:
for child_string in child.tree_string(level+1):
yield child_string
tree = '{121{12}12{211}2}'
for line in Node.from_string(tree).tree_string():
print(line)
Results:
-121122
- 12
- 211

python create a binary search tree using existing function

I'm practicing creating a balanced binary search tree in python.
I already have these below, any idea on how to create a balance_bst funtion that passed a list of unique values that are
sorted in increasing order. It returns a reference to the root of a well-balanced binary search tree:
class LN:
def __init__(self,value,next=None):
self.value = value
self.next = next
def list_to_ll(l):
if l == []:
return None
front = rear = LN(l[0])
for v in l[1:]:
rear.next = LN(v)
rear = rear.next
return front
def str_ll(ll):
answer = ''
while ll != None:
answer += str(ll.value)+'->'
ll = ll.next
return answer + 'None'
# Tree Node class and helper functions (to set up problem)
class TN:
def __init__(self,value,left=None,right=None):
self.value = value
self.left = left
self.right = right
def height(atree):
if atree == None:
return -1
else:
return 1+ max(height(atree.left),height(atree.right))
def size(t):
if t == None:
return 0
else:
return 1 + size(t.left) + size(t.right)
def is_balanced(t):
if t == None:
return True
else:
return abs(size(t.left)-size(t.right)) <= 1 and is_balanced(t.left) and is_balanced(t.right)
def str_tree(atree,indent_char ='.',indent_delta=2):
def str_tree_1(indent,atree):
if atree == None:
return ''
else:
answer = ''
answer += str_tree_1(indent+indent_delta,atree.right)
answer += indent*indent_char+str(atree.value)+'\n'
answer += str_tree_1(indent+indent_delta,atree.left)
return answer
return str_tree_1(0,atree)
How do write the balance_bst?
def balance_bst(l):
Here is what I did:
def build_balanced_bst(l):
if l == None:
return None
else:
middle = len(l) // 2
return TN(l[middle],
build_balanced_bst(l[:middle]),
build_balanced_bst(l[middle + 1:]))
It gives me:
IndexError: list index out of range
How do I fix it?
I'm not going to write it for you since that's not what SO is about, but here's the general idea. Since the list is already sorted, the root should be the element in the middle of the list. Its left child will be the root of the balanced tree consisting of the elements to the left of the root in the list, and the right sub-tree will be the rest.

Linked List Operations

Hello I need help trying to figure out these three functions. I am very new to python.
Assignment:
createList(srcSeq) - creates a linked list from the values
contained in the srcSeq sequence structure and returns the head
reference of the new linked list. The values will be added one at a
time by prepending them to the linked list. myValues = [5, 12, 82,
32, 20] myList = createList(myValues)
size(theList) - given the
head reference (theList), returns the number of elements in the
linked list.
printList(theList) - given the head reference
(theList), prints the values in the linked list from front to back
all on one line with the values separated by commas.
valueAt(theList, index) - returns the value contained in the node at
the given index position where the first value is at position 0, the
second at position 1 and so on. If index is out of range, return
None.
append(theList, value) - appends a new value to the end of
the linked list. Assume the list contains at least one node.
concat(listA, listB) - joins or concatenates two linked lists by
linking the last node of listA to the first node of listB.
split(theList) - given the head reference (theList), splits the
linked list in half to create two smaller linked lists. The head
reference of the linked list created from the second half of the list
is returned. Assume the list contains at least one node. If there is
an odd number of nodes in the linked list, the extra node can be
placed in either of the two new lists.
For the append, concat, do I simply just do. I do not know how to do the split method:
def append (theList, value):
current = self.head
while current.self.next != None:
current = self.next
current.newnode
def concat(listA, listB):
if listA.tail == None:
listA.head = listB.head
else:
listA.tail.next = listB.head
elif listB.head != None:
listA.tail = listB.tail
My Entire Code:
def createList( self ):
self.head = None
temp = ListNode( value )
self.next = newnext
temp.self.next(self.head)
self.head = temp
return self.head
def size( theList ):
current = self.head
count = 0
while current != None:
count = count + 1
current = current.self.next
return count
def printList( theList ):
node = self.head
while node:
print self.value
node = self.next
def valueAt( theList, index ):
current = head
count = 0
while current != None:
if count == index:
return current
def append( theList, value ):
current = self.head
while current.self.next != None:
current = self.next
current.newnode
def concat( listA, listB ):
if listA.tail == None:
listA.head = listB.head
else:
listA.tail.next = listB.head
elif listB.head != None:
listA.tail = listB.tail
def split( theList ):
pass
I think you problem is under-specified. but with what we have :
Splitting a singly linked list:
def split( head ):
middle = head
current = head
index = 0
while current.next != None:
if index % 2:
middle = middle.next
current = current.next
index += 1
result = middle.next
middle.next = None
return result
But to be honest, there is a lot more wrong with what you have so far.
If those lists were Python lists the solution would be really simple:
def split(a):
return a[:len(a)/2], a[len(a)/2:]
And now some explanation :) :
The function returns a tuple of two lists, where each list is one half of the supplied list a.
What I use above is called slicing and you can think of the colon character as of the word until. You can supply two _arguments beginning and end separated by that semicolon.
Example time!
a = [1,2,3,4,5]
a[:2] == [1,2]
a[2:] == [3,4,5]
a[1:3] == [2,3,4]
a[2,-2] == [3]
a[-3,-2] == [3,4]
Isn't slicing great? And it comes for free! One extra trick, if you want to make a copy of a list you can do that with slicing too!
b = a[:]
Boom, done! :)
There is more to slicing, you can have two colons, but that's a story for another time.
PS:
Out of curiosity I did your homework :)
class Node:
def __init__(self, data):
self.data = data
self.next = None
def __str__(self, *args, **kwargs):
return str(self.data)
def create_list(iterable):
next_node = current_node = None
for item in iterable:
current_node = Node(item)
current_node.next = next_node
next_node = current_node
return current_node
def size(head):
count = 0
while head:
head = head.next
count += 1
return count
def print_list(head):
while head:
print(head, end="")
if head.next:
print(" > ", end="")
head = head.next
print(flush=True)
pass
def value_at(head, index):
while (head):
if index < 1:
return head
index -= 1
head = head.next
return None
def append(head, value):
while head:
if not head.next:
head.next = Node(value)
return
head = head.next
def concat(headA, headB):
while headA:
if not headA.next:
headA.next = headB
return
headA = headA.next
def split(head):
center = head
index = 0
while head:
if index % 2:
center = center.next
head = head.next
index += 1
headB = center.next
center.next = None
return headB
def main():
a = create_list([1, 2, 3, 4, 5, 6, 7, 8, 9])
print("Print list::")
print_list(a)
print("\nSize:")
print(size(a))
print("\nValue at:")
print("a[-1]: %d" % value_at(a, -1).data)
print("a[0]: %d" % value_at(a, 0).data)
print("a[1]: %d" % value_at(a, 1).data)
print("a[5]: %d" % value_at(a, 5).data)
print("a[8]: %d" % value_at(a, 8).data)
# print("value # 9 %d"% value_at(my_head,9).data)
print("\nAppend (10):")
print_list(a)
append(a, 10)
print_list(a)
print("\nConcat a, b:")
print_list(a)
b = create_list([11, 12, 13])
print_list(b)
concat(a, b)
print_list(a)
print("\nSplit:")
print_list(a)
print("..into..")
b = split(a)
print_list(a)
print("Size a: %d" % size(a))
print_list(b)
print("Size b: %d" % size(b))
if __name__ == "__main__":
main()

Python - Passing Function Arguments

I am struggling on how to work out how I pass arguments from a function so that I can populate a list in another function - my code is:
infinity = 1000000
invalid_node = -1
startNode = 0
#Values to assign to each node
class Node:
distFromSource = infinity
previous = invalid_node
visited = False
#read in all network nodes
def network():
f = open ('network.txt', 'r')
theNetwork = [[int(node) for node in line.split(',')] for line in f.readlines()]
print theNetwork
return theNetwork
#for each node assign default values
def populateNodeTable():
nodeTable = []
index = 0
f = open('network.txt', 'r')
for line in f:
node = map(int, line.split(','))
nodeTable.append(Node())
print "The previous node is " ,nodeTable[index].previous
print "The distance from source is " ,nodeTable[index].distFromSource
index +=1
nodeTable[startNode].distFromSource = 0
return nodeTable
#find the nearest neighbour to a particular node
def nearestNeighbour(currentNode, theNetwork):
nearestNeighbour = []
nodeIndex = 0
for node in nodeTable:
if node != 0 and currentNode.visited == false:
nearestNeighbour.append(nodeIndex)
nodeIndex +=1
return nearestNeighbour
currentNode = startNode
if __name__ == "__main__":
nodeTable = populateNodeTable()
theNetwork = network()
nearestNeighbour(currentNode, theNetwork)
So, I am trying to fill the nearestNeighbour list in my nearestNeighbour function with a list of nodes nearest to the other nodes. Now, the all the other functions work correctly, with all argument passing functioning as it should.
However, my nearestNeighbour function throws up this error message:
if node != 0 and
theNetwork[currentNode].visited ==
false: AttributeError: 'list' object
has no attribute 'visited'
(Apologies for the layout, haven't quite fathomed the use of the code quotes yet)
class Node(object):
def __init__(self, me, dists):
super(Node,self).__init__()
self.me = me
self.dists = dists
_inf = Network.INF
self.neighbors = sorted((i for i,dist in enumerate(self.dists) if i!=me and dist!=_inf), key=dists.__getitem__)
self.clear()
def clear(self):
self.dist = None
self.prev = None
def nearestNeighbor(self):
try:
return self.neighbors[0]
except IndexError:
return None
def __str__(self):
return "{0}: {1}".format(self.me, self.dists)
class Network(object):
INF = 10**6
#classmethod
def fromFile(cls, fname, delim=None):
with open(fname) as inf:
return cls([[int(dist) for dist in line.split(delim)] for line in inf])
def __init__(self, distArray):
super(Network,self).__init__()
self.nodes = [Node(me,dists) for me,dists in enumerate(distArray)]
def __str__(self):
return '\n'.join(self.nodes)
def floodFill(self, fromNode):
_nodes = self.nodes
for n in _nodes:
n.clear()
_nodes[fromNode].dist = 0
# left as an exercise ;-)
def distances(self):
return [n.dist for n in self.nodes]
def main():
nw = Network.fromFile('network.txt', delim=',')
print(nw)
nw.floodFill(fromNode=0)
print(nw.distances())
if __name__=="__main__":
main()
That's because theNetwork[currentNode] returns a list. In other words: theNetwork is a list of lists.
This is the line where it is done:
theNetwork = [[int(node) for node in line.split(',')] for line in f.readlines()]
theNetwork = [[int(node) for node in line.split(',')] for line in f.readlines()]
theNetwork is a list of lists. A list (theNetwork[currentNode]) doesn't have a visited attribute.
Perhaps you intended something like:
for line in f.readlines():
theNetwork.extend((int(node) for node in line.split(',')))

Categories