Help with transforming arrays and hashes
I'm trying to use Highcharts in my web app, but I'm having some trouble getting my arrays to match the output that highcharts needs, essentially hightcharts needs output like this in it's JS:
series: [{
name: 'person',
data: [1562, 873, 1457]
}, {
name: 'car',
data: [7323, 324, 1233]
}, {
name: 'SUV',
data: [832, 6232, 4432]
}]
Where each item in the data array in this case is a new day, my problem is that my data is organized a bit differently, and trying to transform my data to match this has been a headache. basically my output is like so:
[
{:date=>"Sun, 10 Apr 2011", :object_types=>[
{:count=>4279, :class_name=>"person"},
{:count=>8785, :class_name=>"car"},
{:count=>2153, :class_name=>"SUV"}
]},
{:date=>"Sat, 09 Apr 2011", :object_types=>[
{:count=>12206, :class_name=>"person"},
{:count=>29095, :class_name=>"car"},
{:count=>7565, :class_name=>"SUV"}
]},
{:date=>"Fri, 08 Apr 2011", :object_types=>[
{:count=>4159, :class_name=>"person"}, 开发者_如何学Go
{:count=>8043, :class_name=>"car"},
{:count=>1982, :class_name=>"SUV"}
]}
]
So it seems that I need to primarily have the items first grouped by (in my case) :class_name
, then within that the :count
by day as each item in data
.
I'm having trouble find the the "ruby way" to do this elegantly, I'm not super awesome at manipulating arrays and hashes as you can probably see, but any bit of help in guiding me towards accomplishing this the right way is appreciated.
Secondly, I tried to accomplish this using group()
in my query originally but that doesnt seem to be helping much, thoughts? Another thing I'll have to solve is filling dates with "0" if there are no records for it... but I'll tackle that next I think.
I would use Enumerable#group_by
, because that's the harder part; the rest is just basic transformation:
r = data.flat_map{|h| h[:object_types]}.
group_by{|h| h[:class_name]}.
map do |class_name, hashes|
{:name => class_name, :data => hashes.map{|h| h[:count]}}
end
Note: group_by
is in ActiveRecord or Ruby 1.8.7+. flat_map
is new to Ruby 1.9.2. Use the right version, or require "backports"
.
Something like this should work:
def convert_data(input)
hash = {}
input.each do |o|
o[:object_types].each do |ot|
if hash[ot[:class_name]]
hash[ot[:class_name]] << ot[:count]
else
hash[ot[:class_name]] = [ot[:count]]
end
end
end
hash.map {|k,v| {'name' => k, 'data' => v}}
end
You can call this function with your input data and you've got an object which fits the format you expect for the Highcharts library.
aux = Hash.new(Array.new)
series = Array.new
# After this code the aux hash will look something like this: {:person => [4159, 1231, 255], :suv => [1231, 4123, 5411], :car => [321, 312, 541]}
raw_array.each do |date_hash|
date_hash[:object_types].each do |inf|
aux[inf[:class_name]] << inf[:count]
end
end
aux.each { |k,v| series << {:name => k.to_s, :data => v} }
Then that series array is what you need. Just render it like json.
精彩评论