acts_as_tree icon indicating copy to clipboard operation
acts_as_tree copied to clipboard

Feature: walk_tree_to_children

Open ioquatix opened this issue 9 years ago • 10 comments

I'd like to see something like this included next to TreeWalker::walk_tree:

module ActsAsTree::TreeWalker
    def self.prune
        throw :prune
    end

    def walk_tree_to_children(children, &block)
        marked = Set.new(children.collect(&:self_and_ancestors).flatten)

        walk_tree do |node, level|
            throw :prune unless marked.include?(node)

            yield node, level
        end
    end

    def walk_tree_dfs(where = {}, node = nil, level = 0, &block)
        nodes = (node.nil? ? roots : node.children).where(where)

        nodes.each do |child|
            catch(:prune) do
                yield(child, level)

                walk_tree_dfs(where, child, level + 1, &block)
            end
        end
    end
end

ioquatix avatar Nov 26 '15 10:11 ioquatix

What are you trying to achieve and what would be common use cases?

felixbuenemann avatar Nov 30 '15 22:11 felixbuenemann

Given one or more children, walk a partial tree that goes to all children. A use case is when you have, say, a hierarchy of categories and want to build a sub-tree which allows selection of any specific category or it's ancestors.

ioquatix avatar Nov 30 '15 22:11 ioquatix

Wouldn't this be much more efficient using a path based tree that stores the components of the path as a string or array in the database (like the ancestry gem)?

felixbuenemann avatar Nov 30 '15 23:11 felixbuenemann

It's O(N) where N is the number of children and their ancestors, so while it could be a bit less memory intensive and possibly more efficient pulling data from the database, it's not that inefficient. Honestly it was a quick hack to get what we wanted.

The main benefit of this approach is that it produces the same order as walk_tree but only with specific paths.

It might make sense to use the ancestry gem but we have a data model that suits the acts_as_tree approach.

ioquatix avatar Nov 30 '15 23:11 ioquatix

Maybe it makes sense to implement a generic abort mechanism into both walk_tree_bfs and walk_tree_dfs, so it's easier to build more complex behavior on top of it.

felixbuenemann avatar Dec 01 '15 00:12 felixbuenemann

@felixbuenemann yes as you can see this is part of the proposal.

ioquatix avatar Dec 01 '15 00:12 ioquatix

I'd be open to a PR that adds an :abort or :stop signal to the bfs/dfs methods. I think the walk_tree_to_children itself is a bit use case specific, because there are many possible variants, eg. walk all trees containing at least one of the specified children. One interesting question is where to catch the signal in the bfs case (around a single node or all nodes of the current level).

felixbuenemann avatar Dec 01 '15 15:12 felixbuenemann

I'm not sure if this is really logical for BFS.

ioquatix avatar Jan 25 '16 10:01 ioquatix

I'd be weird to have the feature only work for DFS, don't you think that would be confusing for the users?

felixbuenemann avatar Jan 25 '16 11:01 felixbuenemann

I didn't say it's not possible to implement something, I'm just not sure that it has the same behaviour or is even useful?

ioquatix avatar Jan 25 '16 11:01 ioquatix