Recently I had to traverse a tree, starting from an arbitrary node up to its root. I wrote something along the lines of
breadcrumbs = []
while node is not None:
breadcrumbs.append(node.get_text())
node = node.get_parent()
It has occured to me that it looks a lot like an ugly implementation of list construction that uses
result = []
while node is not None:
result.append(node.get_text())
node = node.next()
instead of the more idiomatic list comprehension
result = [node.get_text() for node in nodes]
This made me wonder whether there is a more idiomatic way of constructing a list from my tree traversal. For completeness (and because the above excerpts are mainly pseudo-code), here is the actual code I used:
model, treeiter = self.treeview.get_selection().get_selected()
breadcrumbs = []
while treeiter is not None:
breadcrumbs.append(model.get_value(treeiter, self.COL_TEXT))
treeiter = model.iter_parent(treeiter)
path = '/'.join(reversed(breadcrumbs))
For context, the first line calls Gtk.TreeSelection.get_selected (one of its return values is called iter
in the API but has nothing to do with Python iterators). My code creates a string from the path selected by the user, eg, "A/b/2"
in the example below:
+- A
| |- a
| \- b
| |- 1
| \- 2 <- selected element
\- B
|- c
\- d
You are true, the tree structure you are using is not very pythonic. But, you can easily turn it to a more pythonic solution using home-made generators .
For instance, to traverse the parents (or ancestors) you can define a iter_parents
function like this:
def iter_parents(node):
while node is not None:
yield node
node = node.get_parent()
With this in hand, you can build the breadcrumbs like this:
breadcrumbs = [node.get_text() for node in iter_parents(branch)]
Here is a small demo:
class Node(object):
def __init__(self, text, parent=None):
self._text = text
self._parent = parent
def get_text(self):
return self._text
def get_parent(self):
return self._parent
branch = Node("c", Node("b", Node("a")))
breadcrumbs = [node.get_text() for node in iter_parents(branch)]
print(breadcrumbs)
# -> ['c', 'b', 'a']
For node.next()
you can define a iter_next()
generator the same way.
edit
Use reverse
to reverse the list, for instance:
breadcrumbs = [node.get_text() for node in iter_parents(branch)]
breadcrumbs.reverse()
print(breadcrumbs)
# -> ['a', 'b', 'c']
Sure, you can wrap your while loop in a generator like this:
def get_parents(node):
while node is not None:
yield node
node = node.get_parent()
Then you can use:
result = [node.get_text() for node in get_parents(nodes)]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.