Wxpython: TreeCtrl: Iteration over a tree - python

I am using the following method to iterate over all the nodes of a wxpython treectrl.
def get_desired_parent(self, name, selectednode = None):
if selectednode == None:
selectednode = self.treeCtrl.RootItem
# First perform the action on the first object separately
childcount = self.treeCtrl.GetChildrenCount(selectednode, False)
if childcount == 0:
return None
(item,cookie) = self.treeCtrl.GetFirstChild(selectednode)
if self.treeCtrl.GetItemText(item) == name:
return item
while childcount > 1:
childcount = childcount - 1
# Then iterate over the rest of objects
(item,cookie) = self.treeCtrl.GetNextChild(item,cookie)
if self.treeCtrl.GetItemText(item) == name:
return item
return None
This problem of excess code becomes even more apparent when I am iterating inside the structure recursively.
Is there another way of performing the same actions in more compact manner, to make my code more concise / pythonic.

You could use a function that is inside this one (in its namespace only) that will check if it matches the conditiin or not. If it does return the item if it doesn't, continue.
Otherwise you could check your condition just after the while line. This way the item variable will be defined by the first child before the loop and evaluated like any other.
Still another way: (or a mix of the two)
(child, cookie) = self.GetFirstChild(item)
while child.IsOk():
do_something(child)
(child, cookie) = self.GetNextChild(item, cookie)

Here a full example that traverses the tree going depth first. The function was bound to the right button.
def OnRightDown(self, event):
def showChildren(item,cookie):
# functions goes recursively down the tree
if item.IsOk():
child, cookie = self.tree.GetFirstChild(item)
while child.IsOk():
child, cookie = self.tree.GetNextChild(child, cookie)
if child:
print(self.tree.GetItemText(child)) #show child label name
showChildren(child,cookie)
pt = event.GetPosition()
item, flags = self.tree.HitTest(pt)
if item:
print(self.tree.GetItemText(item)) #show parent label name
showChildren(item,0) #iterate depth first into the tree

The best way to make your code highly readable here is to make it short and highly functional.
If you need to iterate through all the tree items and do so through depth first. Here's that as a single quick function. Hand it a function that gets each item, and where you start (usually self.root). It's also quite reusable since you might be doing this a lot.
def depth_first_tree(self, funct, item):
(child, cookie) = self.tree.GetFirstChild(item)
while child.IsOk():
self.depth_first_tree(funct, child)
funct(child)
(child, cookie) = self.tree.GetNextChild(item, cookie)

Related

loop/recursion to handle hierarchical structures in Python

I was wondering if there's a more efficient way of looping through a set of objects that might have some dependencies (child-parent relationship) between them, e.g.:
dependencies = [(child1,parent1),(child2,parent2),...]
obj_stack = [{'id':'child1'},{'id':'child2'},{'id':'parent1'},..]
new_stack = [{'id':'child1'},{'id':'child3'}]
check_and_add_to_new_stack(obj) # function that decides if an obj should be added to the new stack
I want to check each obj_stack and add objs into new_stack under two conditions:
it has no parent and check_and_add_to_new_stack(obj) adds it (let's assume it does it correctly)
it has a parent, then add it directly (no need to use the above function)
This means that I need to check if an element has a parent, and then check&add their parent first. If it gets added, then I come back to that element. I am kinda getting stuck on the recursive loop.
Here is the pseudo-code:
def check_and_add_to_new_stack(obj,stack):
if passed_checks(obj):
return add_to_new_stack(obj,stack)
return stack
def myFunction(obj_stack, new_stack, dependencies):
for obj in obj_stack:
if obj is not in new_stack:
if obj has parent in dependencies:
myFunction([parent], new_stack, dependencies)
else: # here the original obj should be thrown back into the function
new_stack += check_and_add_to_new_stack(obj)
return stack
Edit: adding the result that I am expecting and more details:
Let's assume that
passed_checks(parent1) = False
passed_checks(parent2) = True
passed_checks(child1) = True
passed_checks(child2) = False
The expected result is:
myFunction(obj_stack, new_stack, dependencies)
> [{'id':'child1'},{'id':'child3'},{'id':'child2'},{'id':'parent2'}]
Even though passed_checks(child2) = False it has a parent2 for which passed_checks = True, so both get added to the resulting set. child1 was already in new_stack. parent1 did not get added because passed_checks = False.
I think you might be looking for something like this.
walk_ancestry yields node IDs for a given node and all of its parents based on the parents dict (which is basically dict(dependencies) from your original code)
check is your check function – I just copied your condition there
The all_passing set comprehension iterates over all of our known object names (obj_stack in your original code) and uses the built-in any function to see if any of the nodes in that node's ancestry pass the check() test. If so, it's considered passing.
This could be made faster by caching and memoization, but for small enough graphs, I'm pretty sure this works out alright.
def walk_ancestry(parents, node):
while True:
yield node
node = parents.get(node)
if not node:
break
def check(node):
return node in {"parent2", "child1"}
parents = {
"child1": "parent1",
"child2": "parent2",
"parent2": "parent3",
}
all_objects = {
"parent1",
"parent2",
"parent3",
"child1",
"child2",
}
all_passing = {
node
for node in all_objects
if any(check(n) for n in walk_ancestry(parents, node))
}
print(all_passing)
The output is
['parent2', 'child2', 'child1']

Append (self) with stacks in Python classes

I am doing/learning data structures and algorithms and I came across the following code:
class BinaryTree:
def __init__(self, root_data):
self.data = root_data
self.left_child = None
self.right_child = None
def inorder_iterative(self):
inorder_list = []
return inorder_list
def get_right_child(self):
return self.right_child
def get_left_child(self):
return self.left_child
def set_root_val(self, obj):
self.data = obj
def get_root_val(self):
return self.data
def preorder_iterative(self):
pre_ordered_list = [] #use this as result
stack = []
stack.append(self)
while len(stack)>0:
node = stack.pop() #should return a value
pre_ordered_list.append(node.get_root_val())
if node.right_child:
stack.append(node.get_right_child())
if node.left_child:
stack.append(node.get_left_child())
return pre_ordered_list
bn = BinaryTree(1)
bn.left_child = BinaryTree(2)
bn.right_child = BinaryTree(3)
print (bn.preorder_iterative())
I am very lost about stack.append(self) part. I am not sure what is the point of having this line and I don't fully understand the concept of .append(self). I have learnt that self represents the instance of the class.
The purpose of the stack is to simulate recursion.
The initial value placed on the stack is the tree itself (in the form of its root node). Its value is retrieved, and then each subtree is placed on the stack. On the next iteration of the loop, the left child is removed, processed, and replaced with its children, if any. The loop continues as long as there is anything on the stack to process. Once everything on the left side of the tree as been processed, you'll finally start on the right child (placed the stack way at the beginning of the loop).
Compare to a recursive version:
def preorder_recursive(self):
result = [self.get_root_val()]
if node.left_child:
result.extend(node.left_child.preorder_recursive())
if node.right_child:
result.extend(node.right_child.preorder_recursive())
return result
Each recursive call essentially puts self on a stack, allowing the left child (and its descendants) to be processed before eventually returning to the root and moving to its right child.

My recursive function (populates a tree structure) is adding to the root node during every loop/call

I have an algorithm to populate a tree like structure (class: Scan_instance_tree), but unfortunately, during each call, it is incorrectly adding to the root node's children, as well as to the new child nodes created further down in the tree.
As a clue, I saw another thread...
Persistent objects in recursive python functions
...where this problem was mentioned briefly, and it was suggested that the parameters passed had to be mutable. Is that the answer, and how would I do this, in this example???
Here is my current code:
class Field_node(object):
field_phenotype_id = -1
field_name = ''
field_parent_id = -1
child_nodes = []
class Scan_instance_tree(object):
root_node = None
def __init__(self, a_db):
self.root_node = Field_node()
scan_field_values = self.create_scan_field_values(a_db) # This just creates a temporary user-friendly version of a database table
self.build_tree(scan_field_values)
def build_tree(self, a_scan_field_values):
self.root_node.field_name = 'ROOT'
self.add_child_nodes(a_scan_field_values, self.root_node)
def add_child_nodes(self, a_scan_field_values, a_parent_node):
i = 0
while i < len(a_scan_field_values):
if a_scan_field_values[i]['field_parent_dependancy'] == a_parent_node.field_phenotype_id:
#highest_level_children.append(a_scan_field_values.pop(a_scan_field_values.index(scan_field)))
child_node = Field_node()
child_node.field_phenotype_id = a_scan_field_values[i]['field_phenotype_id']
child_node.field_name = a_scan_field_values[i]['field_name']
child_node.field_parent_dependancy = a_scan_field_values[i]['field_parent_dependancy']
a_parent_node.child_nodes.append(child_node)
a_scan_field_values.remove(a_scan_field_values[i])
# RECURSION: get the child nodes
self.add_child_nodes(a_scan_field_values, child_node)
else:
i = i+1
If I remove the recursive call to self.add_child_nodes(...), the root's children are added correctly, ie they only consist of those nodes where the field_parent_dependancy = -1
If I allow the recursive call, the root's children contain all the nodes, regardless of the field_parent_dependancy value.
Best regards
Ann
When you define your Field_node class, the line
child_nodes = []
is actually instantiating a single list as a class attribute, rather than an instance attribute, that will be shared by all instances of the class.
What you should do instead is create instance attributes in __init__, e.g.:
class Field_node(object):
def __init__(self):
self.field_phenotype_id = -1
self.field_name = ''
self.field_parent_id = -1
self.child_nodes = []

How to add to a loop I'm iterating through in Python

I'm searching through a list of scripts, and in each script, I'm parsing it out and among other things, finding the subscripts.
Whenever I find a subscript, I want to add it to the list of scripts I'm searching through.
I came up with this while loop:
while keep_checking == True:
TMP = deepcopy(FILE_LIST)
for fname in TMP:
if not fname in processed:
SCL_FILE = fname
break
handleSCL(SCL_FILE)
processed.add(SCL_FILE)
if processed == FILE_LIST:
keep_checking = False
break
The code above does the job, but I feel like dirty. handleSCL() is searching for the file and adding any new subscripts to FILE_LIST.
Is there a cleaner way of doing this?
I would use a method similar to the A* pathfinding algorithm (just without the pathfinding part).
Open list: placesfiles not yet examined.
Closed list: placesfiles already examined.
Start by adding your first file to openlist; then iterate across every element in openlist. For each element, find all files, and for each new file, check if it's in either list. If it's in neither, add it to openlist. When finished with the element, add it to closedlist.
This is a pretty effective and clean way of going through all of the elements without duplication.
EDIT: upon further consideration, you could use one ordered list, and iterate through it, adding new files to the end of the list. [beginning-current] is the closedlist, and [current-end] is the openlist. A* requires two lists because of sorting and path cost calculations, but you are doing a full search, so you don't need that feature. Then you just need a "add if not exist" for the single list.
Your loop needs some cleanups!
break will break out of the while loop, no need for keep_checking. Also no need for TMP, use it directly in the for loop.
while processed != FILE_LIST:
for fname in deepcopy(FILE_LIST):
if not fname in processed:
SCL_FILE = fname
break
handleSCL(SCL_FILE)
processed.add(SCL_FILE)
will do the same work in less code.
After much thinking, I ended up writing a quick custom queue.
class PerQueue(object):
def __init__(self):
self._init()
self.all_files = set()
self.current = None
self.files = set()
self._init = False
self.cur_files = set()
def _setflag(self, value):
self._init = value
for item in self.all_files:
if item.startswith('ss'):
self.cur_files.add(item)
def _getflag(self):
return self._init
def empty(self):
n = self._empty()
return n
def pushMany(self, itemList):
for item in itemList:
self.push(item)
def push(self, item):
if not item in self.all_files and not item in self.files:
self._put(item)
def pop(self):
# I don't want errors
if not self.empty():
self.current = self._get()
self.all_files.add(self.current)
if self.init:
self.cur_files.add(self.current)
else:
self.current = None
return self.current
def _init(self):
self.files = set()
def _empty(self):
return not self.files
def _get(self):
return self.files.pop()
def _put(self, item):
self.files.add(item)
init = property(_getflag, _setflag)
This allowed me to handle a couple of special conditions (using all_files and cur_files) along with the init flag. At most we have a couple of hundred files to process at any time, so I wasn't worried about size constraints.
This would be way cleaner... and probably unnecessary at this point:
for fname in deepcopy(FILE_LIST):
handleSCL(fname)

Finding certain child in wxTreeCtrl and updating TreeCtrl in wxPython

How can I check if a certain root in a wx.TreeCtrl object has a certain child or not?
I am writing manual functions to update TreeCtrl every time a child is added by user.Is there a way to automate this?
You might want to consider storing the data in some other easily-searchable structure, and using the TreeCtrl just to display it. Otherwise, you can iterate over the children of a TreeCtrl root item like this:
def item_exists(tree, match, root):
item, cookie = tree.GetFirstChild(root)
while item.IsOk():
if tree.GetItemText(item) == match:
return True
#if tree.ItemHasChildren(item):
# if item_exists(tree, match, item):
# return True
item, cookie = tree.GetNextChild(root, cookie)
return False
result = item_exists(tree, 'some text', tree.GetRootItem())
Uncommenting the commented lines will make it a recursive search.
A nicer way to handle recursive tree traversal is to wrap it in a generator object, which you can then re-use to perform any operation you like on your tree nodes:
def walk_branches(tree,root):
""" a generator that recursively yields child nodes of a wx.TreeCtrl """
item, cookie = tree.GetFirstChild(root)
while item.IsOk():
yield item
if tree.ItemHasChildren(item):
walk_branches(tree,item)
item,cookie = tree.GetNextChild(root,cookie)
for node in walk_branches(my_tree,my_root):
# do stuff
For searching by text without recursion :
def GetItemByText(self, search_text, tree_ctrl_instance):
retval = None
root_list = [tree_ctrl_instance.GetRootItem()]
for root_child in root_list:
item, cookie = tree_ctrl_instance.GetFirstChild(root_child)
while item.IsOk():
if tree_ctrl_instance.GetItemText(item) == search_text:
retval = item
break
if tree_ctrl_instance.ItemHasChildren(item):
root_list.append(item)
item, cookie = tree_ctrl_instance.GetNextChild(root_child, cookie)
return retval

Categories