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
How to Avoid Circular Creation of Associated Models in Factory_Girl
How to Get Meta Keywords Using Nokogiri
How to Directly Install a Gem from a Git Repository
Rails - Understanding Application.Js and Application.CSS
Where Is Ruby's Erb Format "Officially" Defined
Using Google Search Rest API in Ruby
Ruby/Active Record: Custom Sorting Order
Why Use Gemspec + Gemfile When Checking for Dependencies
Cucumber Re-Run Failed Scenarios Automatically with a Tag
Ruby-Open3.Popen3/How to Print The Output
Where Are Keywords Defined in Ruby
Gitlab Configuration Issues:: Nginx Unicorn Port Conflict
Access Rake Task Description from Within Task