I'm trying to build some Heatmap specifics charts for ApexChart. So far, I got this Array of Hash, for 3 activities.
[{
:name => "Activity 1",
:data => {
"May 2020" => 37, "June 2020" => 17, "July 2020" => 9, "August 2020" => 18
}
}, {
:name => "Activity 2",
:data => {
"May 2020" => 3
}
}, {
:name => "Activity 3",
:data => {
"July 2020" => 5, "November 2020" => 11
}
}]
On Activity 3, we got only 2 months which are, July
and November
.
My needs would be to fill for each Hash, all missing date, and filling them with 0 as value. My awaited results would be
[{
:name => "Activity 1",
:data => {
"May 2020" => 37, "June 2020" => 17, "July 2020" => 9, "August 2020" => 18, "November 2020" => 0
}
}, {
:name => "Activity 2",
:data => {
"May 2020" => 3, "June 2020" => 0, "July 2020" => 0, "August 2020" => 0, "November 2020" => 0
}
}, {
:name => "Activity 3",
:data => {
"May 2020" => , "June 2020" => 0, "July 2020" => 5, "August 2020" => 0, "November 2020" => 11
}
}]
Yes, September
is missing on purpose. I suppose the best way to achieve this would be to retrieve every months, one by one; Then to fill each arrays with the missing months; But I don't know how to achieve this.
If arr
is your array of hashes, you could construct the desired array in two steps.
require 'date'
date_fmt = "%B %Y"
first_month, last_month = arr.flat_map do |g|
g[:data].keys
end.map { |s| Date.strptime(s, date_fmt) }.minmax
#=> [#<Date: 2020-05-01 ((2458971j,0s,0n),+0s,2299161j)>,
# #<Date: 2020-11-01 ((2459155j,0s,0n),+0s,2299161j)>]
h = (first_month..last_month).map do |d|
d.strftime(date_fmt)
end.product([0]).to_h
#=> {"May 2020"=>0, "June 2020"=>0, "July 2020"=>0, "August 2020"=>0,
# "September 2020"=>0, "October 2020"=>0, "November 2020"=>0}
arr.map { |g| g.merge(:data => h.merge(g[:data])) }
#=> [
# {
# :name=>"Activity 1",
# :data=>{
# "May 2020"=>37, "June 2020"=>17, "July 2020"=>9,
# "August 2020"=>18, "September 2020"=>0,
# "October 2020"=>0, "November 2020"=>0
# }
# },
# {
# :name=>"Activity 2",
# :data=>{
# "May 2020"=>3, "June 2020"=>0, "July 2020"=>0,
# "August 2020"=>0, "September 2020"=>0,
# "October 2020"=>0, "November 2020"=>0
# }
# },
# {
# :name=>"Activity 3",
# :data=>{
# "May 2020"=>0, "June 2020"=>0, "July 2020"=>5,
# "August 2020"=>0, "September 2020"=>0,
# "October 2020"=>0, "November 2020"=>11
# }
# }
# ]
See Enumerable#flat_map, Date::strptime, Array#minmax, Date#strftime, Array#product and Hash#merge. See also DateTime#strptime for date formatting directives.
Note that in the calculation of first_month
and last_month
,
[#<Date: 2020-05-01 ((2458971j,0s,0n),+0s,2299161j)>,
#<Date: 2020-11-01 ((2459155j,0s,0n),+0s,2299161j)>].
map { |d| d.strftime(date_fmt) }
#=> ["May 2020", "November 2020"]