Ruby How to Generate a Tree Structure Form Array

ruby how to generate a tree structure form array?

One example:

#!/usr/bin/env ruby

root = {:id => 0, :title => '', :parent_id => nil}

arr = arr = [
{:id=>1, :title=>"A", :parent_id=>nil},
{:id=>2, :title=>"B", :parent_id=>nil},
{:id=>3, :title=>"A1", :parent_id=>1},
{:id=>4, :title=>"A2", :parent_id=>1},
{:id=>5, :title=>"A11", :parent_id=>3},
{:id=>6, :title=>"12", :parent_id=>3},
{:id=>7, :title=>"A2=121", :parent_id=>6},
{:id=>8, :title=>"A21", :parent_id=>4},
{:id=>9, :title=>"B11", :parent_id=>2},
{:id=>10, :title=>"B12", :parent_id=>2},
]

map = {}

arr.each do |e|
map[e[:id]] = e
end

@@tree = {}

arr.each do |e|
pid = e[:parent_id]
if pid == nil || !map.has_key?(pid)
(@@tree[root] ||= []) << e
else
(@@tree[map[pid]] ||= []) << e
end
end

def print_tree(item, level)
items = @@tree[item]
unless items == nil
indent = level > 0 ? sprintf("%#{level * 2}s", " ") : ""
items.each do |e|
puts "#{indent}-#{e[:title]}"
print_tree(e, level + 1)
end
end
end

print_tree(root, 0)

Output:

-A
-A1
-A11
-12
-A2=121
-A2
-A21
-B
-B11
-B12

Tree data structure persistence in Ruby

Trees work really well with graph databases, such as neo4j: http://neo4j.org/learn/

Neo4j is a graph database, storing data in the nodes and relationships of a graph. The most generic of data structures, a graph elegantly represents any kind of data, preserving the natural structure of the domain.

Ruby has a good interface for the trees:
https://github.com/andreasronge/neo4j

Pacer is a JRuby library that enables very expressive graph traversals. Pacer allows you to create, modify and traverse graphs using very fast and memory efficient stream processing. That also means that almost all processing is done in pure Java, so when it comes the usual Ruby expressiveness vs. speed problem, you can have your cake and eat it too, it's very fast!

https://github.com/pangloss/pacer

Neography is like the neo4j.rb gem and suggested by Ron in the comments (thanks Ron!)

https://github.com/maxdemarzi/neography

Return an array using `form_with`?

You should be able to do this like so:

<%= form_with model: @dog, local: true do |my_form| %>
<% ['labrador','husky'].each do |breed| %>
<%= my_form.check_box :breeds, {multiple: true}, breed%>
<%= my_form.label :breeds, breed.titleize %>
<%end%>
<%= my_form.submit 'Save' %>
<% end %>

The signature for check_box is (object_name, method, options = {}, checked_value = "1", unchecked_value = "0").

Since you are using the form builder the object_name can be omitted as it will be my_form.

So we pass:

  • the method :breeds,
  • the options {multiple: true} so that it creates a collection
  • the checked_value will be the breed name.

ActionView::Helpers::FormHelper#check_box Documentation

How to efficiently build a tree from a flat structure?

Store IDs of the objects in a hash table mapping to the specific object. Enumerate through all the objects and find their parent if it exists and update its parent pointer accordingly.

class MyObject
{ // The actual object
public int ParentID { get; set; }
public int ID { get; set; }
}

class Node
{
public List<Node> Children = new List<Node>();
public Node Parent { get; set; }
public MyObject AssociatedObject { get; set; }
}

IEnumerable<Node> BuildTreeAndGetRoots(List<MyObject> actualObjects)
{
Dictionary<int, Node> lookup = new Dictionary<int, Node>();
actualObjects.ForEach(x => lookup.Add(x.ID, new Node { AssociatedObject = x }));
foreach (var item in lookup.Values) {
Node proposedParent;
if (lookup.TryGetValue(item.AssociatedObject.ParentID, out proposedParent)) {
item.Parent = proposedParent;
proposedParent.Children.Add(item);
}
}
return lookup.Values.Where(x => x.Parent == null);
}

Show the structure of a large nested hash

I think #transform_values is perfect variant to help here:

def deep_values_transform(hash)
hash.transform_values do |value|
if value.is_a?(Hash)
deep_values_transform(value)
else
value.class
end
end
end

> hash = {
days: {
monday: [1,2,3,4],
tuesday: [1,2,3,4]
},
movies: {
action: ['Avengers', 'My Little Pony'],
adventure: ['Dorra The Explorer'],
comedy: ['Star Wars']
},
data_quality: 0.9,
verified: true
}

> deep_values_transform hash
=> {:days=>{:monday=>Array, :tuesday=>Array}, :movies=>{:action=>Array, :adventure=>Array, :comedy=>Array}, :data_quality=>Float, :verified=>TrueClass}

map function for ruby tree class

If you can implement an each method for your class, then include Enumerable, you'll inherit all sorts of magical goodness including map.

Implement <=> and you'll gain even more.

Enumerable is your friend.


EDIT:

If you look at what happens when Hash#map is called, the hash is transformed into an array of arrays:

>> hash = {'a' => 1, 'b' => 2} #=> {"a"=>1, "b"=>2}
>> hash.map{|n| n} #=> [["a", 1], ["b", 2]]

It is up to the developer to mop-up afterward and optionally rebuild the transformed hash. It's easy because of how Hash[] works.

>> Hash[*hash.map{|n| n}.flatten] #=> {"a"=>1, "b"=>2}

If it was me, I'd write a way to take an array of arrays, and rebuild your tree. That way your each method would allow you to include Enumerable which would create map. You could call it, and then rebuild the tree on the fly. Look at how Hash#[] is used and you should be on your way to implementing something similar for your code.



Related Topics



Leave a reply



Submit