I've been hitting my head up against this one all day. Time for new eyes.
I have a tree-structured model using the ancestry gem. Works great and calling TreeNode.arrange
returns a tidy little hash that is a nested tree. The problem is I'm looking for a "flattened tree" for lack of a better description. For example:
Node1
Node2
Node3
Node4
Node5
Node6
Node7
Node8
Node9
As opposed to a more traditional
Node1
Node2
Node3...
So in other words I only want to "indent" my tree if there is a branch point (more than one child). I figured the best way to do this is a recursive function. I've tried several variants and I am just drawing a blank on this one :-\
def walk_until_fork(tree_hash,&blk)
tree_hash.each do |node,children|
yield node.title
if children.keys.length > 1
#fork point
children.each do |subnode,grandchilden|
walk_until_fork(grandchilden,&blk)
yield subnode.title
end
else
walk_until_fork(children,&blk)
end
end
end
The result of calling that test code is the fork points end up at the bottom of the output :-\
What I'd really like to see is a hash structure like that but the only keys that should have children is where a branching happened (one branch continues at that current level and each n branch after that forks).
I'm not sure if I'm being clear. I'll clarify with any questions if needed.
Deleted everything I and started over with a new approach. I'll refactor this later most likly but here was the basic idea.
def walk_until_fork(tree_hash, root_node = nil)
root_node ||= ActiveSupport::OrderedHash.new
tree_hash.each do |node,children|
more_than_one = false
parent_node = root_node[node] = ActiveSupport::OrderedHash.new
children.each do |k,v|
fork_node = more_than_one ? parent_node : root_node
walk_until_fork({k => v},fork_node)
more_than_one = true
end
end
root_node
end
Then I just call with:
walk_until_fork(self.arrange)
The code passes a hash reference around to the current root, changing it to a new hash only there is more then one child.