Füllen Sie ein Array von Hashs mit fehlenden Werten

Nov 25 2020

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, Julyund 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, Septemberfehlt 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

1 CarySwoveland Nov 26 2020 at 02:57

Wenn arres 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_monthund 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"]
1 KARASZIIstván Nov 25 2020 at 18:27

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, Arraybei der die HashWerte mit einem Standardwert initialisiert werden:

data_with_default = data.map do |d|
  {
    name: d[:name],
    data: Hash.new(0).update(d[:data])
  }
end
BenTrewern Nov 25 2020 at 18:48

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] }] } }