Füllen Sie ein Array von Hashs mit fehlenden Werten
Ich versuche, einige Heatmap-Diagramme für ApexChart zu erstellen . Bisher habe ich dieses Array von Hash für 3 Aktivitäten erhalten.
[{
: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
}
}]
Bei Aktivität 3 haben wir nur 2 Monate, July
und November
.
Meine Bedürfnisse wären, für jeden Hash alle fehlenden Daten zu füllen und sie mit 0 als Wert zu füllen. Meine erwarteten Ergebnisse wären
[{
: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
}
}]
Ja, September
fehlt absichtlich. Ich nehme an, der beste Weg, dies zu erreichen, wäre, jeden Monat nacheinander abzurufen. Füllen Sie dann jedes Array mit den fehlenden Monaten. Aber ich weiß nicht, wie ich das erreichen soll.
Antworten
Wenn arr
es sich um ein Array von Hashes handelt, können Sie das gewünschte Array in zwei Schritten erstellen.
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
# }
# }
# ]
Siehe Enumerable # flat_map , Date :: strptime , Array # minmax , Date # strftime , Array # product und Hash # merge . Siehe auch DateTime # strptime für Datumsformatierungsanweisungen.
Beachten Sie, dass bei der Berechnung von first_month
und 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"]
Sie können dies durch etwas Ähnliches erreichen, indem Sie zuerst die Monate abrufen und dann die Array-Elemente ändern, die in Ihrem Fall Hashes sind:
months = data.flat_map { |d| d[:data].keys }.to_set
data.each do |d|
months.each do |month|
d[:data][month] = 0 unless d[:data].key?(month)
end
end
Sie können auch eine neue erstellen, Array
bei der die Hash
Werte mit einem Standardwert initialisiert werden:
data_with_default = data.map do |d|
{
name: d[:name],
data: Hash.new(0).update(d[:data])
}
end
Versuche Folgendes:
a = [{
: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
}
}]
months = ['May 2020', 'June 2020', 'July 2020', 'August 2020', 'November 2020']
puts a.map { |h| { name: h[:name], data: Hash[months.map { |m| [m, h[:data][m] ? h[:data][m] : 0] }] } }