Error when Searching trees iterively - python

I need to search a tree by checking if the sum of the branches from a node is greater than zero. However, I'm running into a problem with the sum - I get a type error (int object is not callable) on the
branch_sum = [t[0] for t in current]
line. I thought it was because eventually I'll get a single node
current = [[1,'b']]
(for example), and so I added the if/else statement. I.e. I thought that I was trying to sum something that looked like this:
first = [1]
However, the problem still persists. I'm unsure of what could be causing this.
For reference, current is a list of lists, with the first slot is the node data the second slot is a node id (in the inner list). The group() function groups the data on a node based on the id of the sub-nodes (left subnodes have ids beginning with 1, right have ids beginning with 0).
The tree I'm searching is stored as a list of lists like:
tree = [[0, '1'], [1,'01'], [0,'001']]
i.e. it's a set of Huffman Codes.
from collections import deque
def group(items):
right = [[item[0],item[1][1:]] for item in items if item[1].startswith('1')]
left = [[item[0],item[1][1:]] for item in items if item[1].startswith('0')]
return left, right
def search(node):
loops = 0
to_crawl = deque(group(node))
while to_crawl:
current = to_crawl.popleft() # this is the left branch of the tree
branch_sum = 0
if len(current)==1:
branch_sum = sum([t for t in current])
else:
branch_sum = sum([t[0] for t in current])
if branch_sum !=0 :
l,r = group(current)
to_crawl.extendleft(r)
to_crawl.extendleft(l)
loops += 1
return loops
Here's what I'm trying to do:
GIven a tree, with a lot of the data being 0, find the 1. To do this, split the tree into two branches (via the group() function) and push onto deque. Pop a branch off the deque, then sum the data in the branch. If the sum is not zero split the branch into two sub branches, push the sub branches onto the deque. Keep on doing this until I've found the non-zero datum. I should end up with a single item of the form [1,'101'] in the deque when I exit.

I strongly assume that the error says
TypeError: 'int' object is not iterable
because you end up passing a 2-tuple as node to
to_crawl = deque(group(node))
which gives you a 2-element deque. Then
current = to_crawl.popleft()
gives you a single element (an integer) as current. This is clearly not iterable, which leads to the given error.
Side note: For brevity, you can use sum like this
sum(current)
instead of
sum([x for x in current])

Related

For merging 2 sorted linked list in reverse order I am getting AttributeError 'NoneType' object has no attribute 'next' for some of the testcases. Why

I am looking at the Merge 2 sorted linked list in reverse order practice challenge on Geeks for Geeks:
Given two linked lists of size N and M, which are sorted in non-decreasing order. The task is to merge them in such a way that the resulting list is in decreasing order.
Input:
First line of input contains number of testcases T. For each testcase, first line of input conatains [sic] length of both linked lists N and M respectively. Next two lines contains N and M elements of two linked lists.
Output:
For each testcase, print the merged linked list which is in non-increasing order.
User Task:
The task is to complete the function mergeResult() which takes reference to the heads of both linked list and returns the pointer to the merged linked list.
My Approach
I am trying to first merge the list in ascending order and then reverse it.
It is working for most of the test cases but failing for few with error:-
line 21, in mergeResult
p3=p3.next
AttributeError: 'NoneType' object has no attribute 'next'
def mergeResult(h1,h2):
p1=h1
p2=h2
node=Node(-1)
p3=node
while p1!=None and p2!=None:
if p1.data<p2.data:
p3.next=p1
p1=p1.next
elif p2.data<p1.data:
p3.next=p2
p2=p2.next
p3=p3.next
if p1!=None:
p3.next=p1
if p2!=None:
p3.next=p2
head=node.next
curr=head
prev=None
next=None
while curr:
next=curr.next
curr.next=prev
prev=curr
curr=next
head=prev
return head
What am I doing wrong here? Is there any other approach for this problem?
The problem is in this line:
elif p2.data<p1.data:
There shouldn't be a condition here, as you want to deal with all remaining cases. Right now you don't treat the case where p2.data is equal to p1.data. So change the above line to:
else:
This will fix the issue.
Alternative
There is a shorter way to achieve the result: instead of reversing the list in a second phase, insert the nodes in reverse order directly. That way you can deal with the job in one loop instead of two. You should then continue the loop as long as one of the references is not None, so the while condition becomes an or. Then in the if condition you need to consider that one of the two could be None. Finally, you don't really need to introduce p1 and p2 variables: just use the already given h1 and h2.
This solution also doesn't need the temporary "sentinel" node (the one with value -1).
def mergeResult(h1,h2):
result = None
while h1 or h2:
if not h2 or (h1 is not None and h1.data < h2.data):
h1.next, result, h1 = result, h1, h1.next
else:
h2.next, result, h2 = result, h2, h2.next
return result
So here h1 (or h2) is prepended to the current result list. After it is prepended, the result reference is put to that prepended node. The multiple assignment is such that h1 (or h2) will still walk to the (original) next node, before that node's next reference is adjusted. You can of course also do this with separate assignments, but then you need a temporary variable:
def mergeResult(h1,h2):
result = None
while h1 or h2:
if not h2 or (h1 is not None and h1.data < h2.data):
nxt = h1.next
h1.next = result
result = h1
h1 = nxt
else:
nxt = h2.next
h2.next = result
result = h2
h2 = nxt
return result
In the while loop of mergeResult, you need to check whether p1.data == p2.data. Currently, you are not checking this, so when p1.data == p2.data, p3.next is not set (and thus maintains its default value of None). This means that p3 gets set to None, and as the error shows, p3.next (i.e. None.next) does not work.

Print out tree contents so that each parent covers all its children

Part of the problem requires that each parent should cover all of its children. If the parent string is too short underscores are added. Any remaining space has periods added.
* Note: input trees can have any number of children *
So far I have a function (add_brackets) that adds brackets to each string per the specifications for the problem. It is in these brackets the underscores are added if needed.
The second function (underscores) calculates how many underscores are required.
The last function prints out the tree in level-order recursively.
My current thoughts are that I need to apply the underscores function in the add_brackets function and have add_brackets when printing in the level-order but I am having trouble putting it all together.
def add_brackets(x):
row = ''
for i in x:
row = row+'['+i+']'
return row
def underscores(node):
parent, children = node
num = 0
for child in children:
num += len(child)+2
num -= 2
if len(parent) > canlen:
return
return '_'*num
def level_order(*nodes):
if not nodes:
return
labels,childrens = zip(*nodes)
print(add_brackets(labels))
flattened_children = [c for children in childrens for c children]
level_order(*flattened_children)
tree = eval(input('Enter tree: '))
print(level_order(tree))
The following tree,
tree = ("hello", (("a", ()), ("b", (("cde", ()), ("fg", ())))))
Should have output,
[hello_____]
[a][b______]
...[cde][fg]
and,
tree = ("supercalifragilisticexpialidocious",(("a",(("b",(("candy",()),)),("onomatopoeia",()),)),("d",(("egg",(("f",()),)),)),))
Should be,
[supercalifragilisticexpialidocious]
[a__________________][d__]..........
[b____][onomatopoeia][egg]..........
[candy]..............[f]............
How do I add the correct amount of underscores and periods?
I worked out the problem you describe and it was more work than I anticipated (though less than 1,500 bytes of code.) The basic model is to work bottom up to get the underscores and then bottom down to get the padding. Here's an outline of the functions I defined to solve it:
def height_tree(node):
Recursive, depth first. Simple code to calculate the height of the tree. This is only needed by the next function to distinguish between a node like [a] that has no children but needs one faked up for the padding to work and and a node that has no children for which we don't want to add fake ones.
def covered_tree(node, level=0):
Recursive, depth first. Recurses first then works out underscore coverage widths. If level is defaulted to zero, sets it to height_tree() above. Returns a valid tree:
('[hello_____]', (('[a]', (('...', ()),)), ('[b______]', (('[cde]', ()), ('[fg]', ())))))
but parent strings have been extended with brackets and underscores. Gives nodes like [a] and [onomatopoeia] faked up childred consisting of period padding.
def padded_tree(node, tail=True):
Recursive, depth first. Works out padding first then recurses. Only handles the padding at the right most end of branch, internal padding was handled by covered_tree() above. Returns a valid tree:
('[supercalifragilisticexpialidocious]', (('[a__________________]', (('[b____]', (('[candy]', ()),)), ('[onomatopoeia]', (('..............', ()),)))), ('[d__]..........', (('[egg]..........', (('[f]............', ()),)),))))
but parent strings have been extended with period padding.
def print_tree(node, line_width=0):
Iterative, breadth first. Prints tree, setting line_width to the width of the top node, as it covers all. Counts down printing width until it hits zero, outputs a newline, and resets the printing width back to line_width.
OUTPUT
>>> tree = ("hello", (("a", ()), ("b", (("cde", ()), ("fg", ())))))
>>> print_tree(padded_tree(covered_tree(tree)))
[hello_____]
[a][b______]
...[cde][fg]
>>>
>>> tree = ("supercalifragilisticexpialidocious",(("a",(("b",(("candy",()),)),("onomatopoeia",()),)),("d",(("egg",(("f",()),)),)),))
>>> print_tree(padded_tree(covered_tree(tree)))
[supercalifragilisticexpialidocious]
[a__________________][d__]..........
[b____][onomatopoeia][egg]..........
[candy]..............[f]............
>>>
I don't quite understand how covered_tree function works. Can you
elaborate please?
Since this is a critical function, let's break it down:
def covered_tree(node, level=0):
If level is zero, the default, set level to the result of height_tree(node). Split node up into its two parts, a parent (label) and a list of children (nodes).
Do our recursion, creating a new list of children (nodes) that is the result of calling covered_tree() on each child, but passing level - 1 explicitly. For each of these new children, sum the len() (width) of the their labels. From this tally, subtract the len() (width) of our parent label and a width of 2 to account for the brackets.
Now we're ready to create our return node. It's a tuple that consists of: our parent formatted with brackets plus the number of underscores we just calculated in the previous step; our new list of children. However, if there are no children, and level is greater than one, then instead of empty children, we return a faked up list of children consisting of a child whose label is a string of periods, and whose own children are an empty tuple (i.e. our empty list of children.) The length of this period string is again len() (width) of our parent label plus 2 to account for brackets:
('[hello_____]', (('[a]', (('...', ()),)), ('[b______]', (('[cde]', ()), ('[fg]', ())))))

Find the smallest item in a singly-linked List and move to the head?

I had a quiz recently and this is what the question looked like:-
You may use the following Node class:
class Node:
"""Lightweight, nonpublic class for storing a singly linked node."""
__slots__ = 'element', 'next' # streamline memory usage
def __init__(self, element, next): # initialize node's fields
self.element = element # reference to user's element
self.next = next # reference to next node
Assume you have a singly-linked list of unique integers. Write a Python method that traverses this list to find the smallest element, removes the node that contains that value, and inserts the smallest value in a new node at the front of the list. Finally, return the head pointer. For simplicity, you may assume that the node containing the smallest value is not already at the head of the list (ie, you will never have to remove the head node and re-add it again).
Your method will be passed the head of the list as a parameter (of type Node), as in the following method signature:
def moveSmallest(head):
You may use only the Node class; no other methods (like size(), etc) are available. Furthermore, the only pointer you have is head (passed in as a parameter); you do not have access to a tail pointer.
For example, if the list contains:
5 → 2 → 1 → 3
the resulting list will contain:
1 → 5 → 2 → 3
Hint 1: There are several parts to this question; break the problem down and think about how to do each part separately.
Hint 2: If you need to exit from a loop early, you can use the break command.
Hint 3: For an empty list or a list with only one element, there is nothing to do!
My answer:
def moveSmallest(h):
if h==None or h.next==None:
return h
# find part
temp=h
myList=[]
while temp!=None:
myList.append(temp.element)
temp=temp.next
myList.sort()
sv=myList[0]
# remove part
if h.element==sv and h.next!=None:
h=h.next
else:
start=h
while start!=None:
if start.next.element==sv and start.next.next!=None:
start.next=start.next.next
break
if start.next.element==sv and start.next.next==None:
start.next=None
break
start=start.next
# Insert part
newNode=Node(sv)
newNode.next=h
h=newNode
return h
Mark received=10/30
Feedback on my answer:
"Not supposed to use sorting; searching the list should be the way we've covered in class.
You're advancing too far ahead in the list without checking whether nodes exist.
Review the 'singly-linked list' slides and answer this question as the examples suggest."
As you can see I am finding the element in the list and removing it and then adding it to the list as a head node. I ran this code and it works fine. As you can see in the feedback he says "You're advancing too far ahead in the list without checking whether nodes exist." which is taken care by the first if statement in my answer and for "Not supposed to use sorting; searching the list should be the way we've covered in class." I believe my mistake was to use the list at the first place but given the code the final score should be or be more than 20/30. Can you guys please check this or give your opinion on this feedback?
As you can see in the feedback he says "You're advancing too far ahead
in the list without checking whether nodes exist." which is taken care
by the first if statement in my answer
It's not taken care of. The first if-statement of your function just checks to see if the head exists and that the node following the head exists as well (basically, asserting that you have at least two nodes in the linked list).
What you have:
if h.element==sv and h.next!=None:
h=h.next
else:
start=h
while start!=None:
if start.next.element==sv and start.next.next!=None:
If you enter the while loop, you only know the following things:
Your linked list has at least two elements
h.element != sv or h.next == None
The current node is not None
The node following the current node (start.next), however, may be None at some point - when you reach the end of your linked list. Therefore, you are trying to access a node that doesn't exist.
Here's how I would have done it. I haven't tested this, but I'm pretty sure this works:
def moveSmallest(head):
if head is None or head.next is None:
return head
# First, determine the smallest element.
# To do this, we need to visit each node once (except the head).
# Create a cursor that "iterates" through the nodes
# (The cursor can start at the 2nd element because we're guaranteed the head will never have the smallest element.)
cursor = head.next
current_minimum = head.next.element
while cursor is not None:
if current_minimum > cursor.element:
# We've found the new minimum.
current_minimum = cursor.element
cursor = cursor.next
# At this point, current_minimum is the smallest element.
# Next, go through the linked list again until right before we reach the node with the smallest element.
cursor = head
while cursor.next is not None:
if cursor.next.element == current_minimum:
# We want to reconnect the arrows.
if cursor.next.next is None:
cursor.next = None
else:
cursor.next = cursor.next.next
break
new_node = Node(current_minimum, head)
head = new_node
return head

Unions in Python

Say I'm given a tuple of strings, representing relationships between objects, for example:
connections = ("dr101-mr99", "mr99-out00", "dr101-out00", "scout1-scout2","scout3-scout1", "scout1-scout4", "scout4-sscout", "sscout-super")
each dash "-" shows a relationship between the two items in the string. Then I'm given two items:
first = "scout2"
second = "scout3"
How might I go about finding if first and second are interrelated, meaning I could find a path that connects them, not necessarily if they are just in a string group.
You can try concatenating the strings and using the in operator to check if it is an element of the tuple connections:
if first + "-" + second in connections:
# ...
Edit:
You can also use the join() function:
if "-".join((first, second)) in connections:
# ...
If you plan on doing this any number of times, I'd consider frozensets...
connections_set = set(frozenset(c.split('-')) for c in connections)
Now you can do something like:
if frozenset((first, second)) in connections_set:
...
and you have an O(1) solution (plus the O(N) upfront investment). Note that I'm assuming the order of the pairs is irrelevant. If it's relevant, just use a tuple instead of frozenset and you're good to go.
If you actually need to walk through a graph, an adjacency list implementation might be a little better.
from collections import defaultdict
adjacency_dict = defaultdict(list)
for c in connections:
left, right = c.split('-')
adjacency_dict[left].append(right)
# if undirected: adjacency_dict[right].append(left)
class DFS(object):
def __init__(self, graph):
self.graph = graph
def is_connected(self, node1, node2):
self._seen = set()
self._walk_connections(node1)
output = node2 in self._seen
del self._seen
return output
def _walk_connections(self, node):
if node in self._seen:
return
self._seen.add(node)
for subnode in self.graph[node]:
self._walk_connections(subnode)
print DFS(adjacency_dict).is_connected()
Note that this implementation is definitely suboptimal (I don't stop when I found the node I'm looking for for example) -- and I don't check for an optimal path from node1 to node2. For that, you'd want something like Dijkstra's algorithm
You could use a set of pairs (tuples):
connections = {("dr101", "mr99"), ("mr99", "out00"), ("dr101", "out00")} # ...
if ("scout2", "scout3") in connections:
print "scout2-scout3 in connections"
This only works if the 2 elements are already in the right order, though, because ("scout3", "scout2") != ("scout2", "scout3"), but maybe this is what you want.
If the order of the items in the connection is not significant, you can use a set of frozensets instead (see mgilson's answer). Then you can look up pairs of item regardless of which order they appear in, but the order of the original pairs in connections is lost.

py2neo how to retrieve a node based on node's property?

I've found related methods:
find - doesn't work because this version of neo4j doesn't support labels.
match - doesn't work because I cannot specify a relation, because the node has no relations yet.
match_one - same as match.
node - doesn't work because I don't know the id of the node.
I need an equivalent of:
start n = node(*) where n.name? = "wvxvw" return n;
Cypher query. Seems like it should be basic, but it really isn't...
PS. I'm opposed to using Cypher for too many reasons to mention. So that's not an option either.
Well, you should create indexes so that your start nodes are reduced. This will be automatically taken care of with the use of labels, but in the meantime, there can be a work around.
Create an index, say "label", which will have keys pointing to the different types of nodes you will have (in your case, say 'Person')
Now while searching you can write the following query :
START n = node:label(key_name='Person') WHERE n.name = 'wvxvw' RETURN n; //key_name is the key's name you will assign while creating the node.
user797257 seems to be out of the game, but I think this could still be useful:
If you want to get nodes, you need to create an index. An index in Neo4j is the same as in MySQL or any other database (If I understand correctly). Labels are basically auto-indexes, but an index offers additional speed. (I use both).
somewhere on top, or in neo4j itself create an index:
index = graph_db.get_or_create_index(neo4j.Node, "index_name")
Then, create your node as usual, but do add it to the index:
new_node = batch.create(node({"key":"value"}))
batch.add_indexed_node(index, "key", "value", new_node)
Now, if you need to find your new_node, execute this:
new_node_ref = index.get("key", "value")
This returns a list. new_node_ref[0] has the top item, in case you want/expect a single node.
use selector to obtain node from the graph
The following code fetches the first node from list of nodes matching the search
selector = NodeSelector(graph)
node = selector.select("Label",key='value')
nodelist=list(node)
m_node=node.first()
using py2neo, this hacky function will iterate through the properties and values and labels gradually eliminating all nodes that don't match each criteria submitted. The final result will be a list of all (if any) nodes that match all the properties and labels supplied.
def find_multiProp(graph, *labels, **properties):
results = None
for l in labels:
for k,v in properties.iteritems():
if results == None:
genNodes = lambda l,k,v: graph.find(l, property_key=k, property_value=v)
results = [r for r in genNodes(l,k,v)]
continue
prevResults = results
results = [n for n in genNodes(l,k,v) if n in prevResults]
return results
see my other answer for creating a merge_one() that will accept multiple properties...

Categories

Resources