Reputation: 1085
I'm stuck on what is the best way to re-arrange my ruby hash.
The main goal is to group results from mysql by month and count.
To do it, i make this request:
@data = Model.find(params[:id])
.jobs
.group('year(created_at)')
.group('month(created_at)')
.count(:id)
Which gives me:
#=> {[2013, 12]=>9, [2014, 1]=>4, [2014, 3]=>3,
# [2014, 4]=>1, [2014, 6]=>1, [2014, 7]=>1, [2014, 10]=>2}
I'm trying to have a cleaner hash or array to convert to json, where the years are not duplicated.
How can I have something workable like {"Year" => [Month,Count value]}
? (or other form)
Idea? (I run ruby 2.2)
Upvotes: 2
Views: 118
Reputation: 565
The answer proposed by @mudosobwa might be correct, but because your target is a json file, you may want some 'named' keys. I suggest you this one :
formated_results = @data.group_by{|k, v| k[0]}.collect{|k,v| {year: k, datas: v.collect{|vv| {month: vv.first.last, count: vv.last}}}}
# {:year=>2013, :datas=>[{:month=>12, :count=>9}]}
# {:year=>2014, :datas=>[{:month=>1, :count=>4}, {:month=>3, :count=>3}, {:month=>4, :count=>1}, {:month=>6, :count=>1}, {:month=>7, :count=>1}, {:month=>10, :count=>2}]}
EDIT : An other solution without the group_by method :
formated_results = Hash.new{|h,k| h[k] = []}
@data.each{|k,v| formated_results[k[0]] << {month: k[1], count: v}}
formated_results = formated_results.collect{|k, v| {year: k, datas: v}}
# {:year=>2013, :datas=>[{:month=>12, :count=>9}]}
# {:year=>2014, :datas=>[{:month=>1, :count=>4}, {:month=>3, :count=>3}, {:month=>4, :count=>1}, {:month=>6, :count=>1}, {:month=>7, :count=>1}, {:month=>10, :count=>2}]}
Then you just have to
formated_results.to_json
The json result shall be :
[
{
"year": 2013,
"datas": [
{ "month": 12, "count": 9 }
]
},
{
"year": 2014,
"datas": [
{ "month": 1, "count": 4 },
{ "month": 3, "count": 3 },
{ "month": 4, "count": 1 },
{ "month": 6, "count": 1 },
{ "month": 7, "count": 1 },
{ "month": 10, "count": 2 }
]
}
]
Upvotes: 4
Reputation: 121000
Given you already have your hash in @data
, you might:
@data.inject({}) do |memo, ((y, m), cnt)|
(memo[y] ||= {})[m] = cnt
memo
end
#⇒ {
# 2013 => {12 => 9},
# 2014 => {1 => 4, 10 => 2, 3 => 3, 4 => 1, 6 => 1, 7 => 1}
# }
As it was noted by @Surya in comments, it should be hash Year => Hash[Month, Count]
. While you still want to have arrays of Month, Count
:
@data.inject({}) do |memo, ((y, m), cnt)|
memo[y] ||= []
memo[y] << [m, cnt]
memo
end
To json:
require 'json'
result.to_json
#=> "{\"2013\":{\"12\":9},\"2014\":{\"1\":4,\"3\":3,\"4\":1,\"6\":1,\"7\":1,\"10\":2}}"
Upvotes: 2
Reputation: 1364
@data.to_a.group_by{|ym, c| ym.first }.map{|year, months| [year,months.map{|m,cnt| [m.last, cnt] }] }.to_h
=> {2013=>[[12, 9]], 2014=>[[1, 4], [3, 3], [4, 1], [6, 1], [7, 1], [10, 2]]}
Upvotes: -1