How to rotate an array with ActiveRecord objects 90 °
I have
@my_objects = [ #<MyObject id: 1, title: "Blah1">,
#<MyObject id: 2, title: "Blah2">,
#<MyObject id: 3, title: "Blah3">,
#<MyObject id: 4, title: "Blah4"> ]
I need to enable it:
@my_objects = { :id => [ 1, 2, 3, 4],
:title => [ "Blah1" ... ] }
Is there a built-in method or some kind of standard approach?
I can only imagine this
@my_objects.inject({}){ |h, c| c.attributes.each{ |k,v| h[k] ||= []; h[k] << v }; h }
This question arose when I thought about this particular question.
First, use Enumerable # map (something like @o.map { |e| [e.id, e.title] }) to get an ActiveRecord array in a simplified pure Ruby object that looks like this:
a = [[1, "Blah1"], [2, "Blah2"], [3, "Blah3"], [4, "Blah4"]]
Then:
a.transpose.zip([:id, :title]).inject({}) { |m, (v,k)| m[k] = v; m }
Alternative solution: It may be less complicated and easier to read if instead you just did something prosaic:
i, t = a.transpose
{ :id => i, :title => t }
Anyway:
=> {:title=>["Blah1", "Blah2", "Blah3", "Blah4"], :id=>[1, 2, 3, 4]}
Update: Tokland has a refinement worth mentioning:
Hash[[:id, :title].zip(a.transpose)]
Functional approach (not everyone!):
pairs = @my_objects.map { |obj| obj.attributes.to_a }.flatten(1)
Hash[pairs.group_by(&:first).map { |k, vs| [k, vs.map(&:second)] }]
#=> {:title=>["Blah1", "Blah2", "Blah3", "Blah4"], :id=>[1, 2, 3, 4]}
As usual, Facets allows you to write more pleasant code; in this case, Enumerable#map_byavoid using the ugly and confusing template group_by+ map+ map:
@my_objects.map { |obj| obj.attributes.to_a }.flatten(1).map_by { |k, v| [k, v] }
#=> {:title=>["Blah1", "Blah2", "Blah3", "Blah4"], :id=>[1, 2, 3, 4]}