用缺失值填充哈希数组
Fill an array of hash with missing values
我正在尝试为 ApexChart 构建一些热图细节图表。到目前为止,我得到了这个哈希数组,用于 3 个活动。
[{
: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
}
}]
在 Activity 3,我们只有 2 个月,即 July
和 November
。
我的需要是填充每个哈希值,所有缺失的日期,并用 0 作为值填充它们。我期待的结果是
[{
: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
}
}]
是的,September
是故意遗漏的。我认为实现这一目标的最佳方法是每个月一个接一个地检索;然后用缺失的月份填充每个数组;但是我不知道怎么实现。
您可以通过类似的方式实现此目的,首先获取月份,然后修改在您的情况下为散列的数组项:
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
您还可以创建一个新的 Array
,其中 Hash
值使用默认值初始化:
data_with_default = data.map do |d|
{
name: d[:name],
data: Hash.new(0).update(d[:data])
}
end
尝试以下操作:
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] }] } }
如果 arr
是您的哈希数组,您可以分两步构建所需的数组。
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
# }
# }
# ]
有关日期格式化指令,请参阅 Enumerable#flat_map, Date::strptime, Array#minmax, Date#strftime, Array#product and Hash#merge. See also DateTime#strptime。
注意在first_month
和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"]
我正在尝试为 ApexChart 构建一些热图细节图表。到目前为止,我得到了这个哈希数组,用于 3 个活动。
[{
: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
}
}]
在 Activity 3,我们只有 2 个月,即 July
和 November
。
我的需要是填充每个哈希值,所有缺失的日期,并用 0 作为值填充它们。我期待的结果是
[{
: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
}
}]
是的,September
是故意遗漏的。我认为实现这一目标的最佳方法是每个月一个接一个地检索;然后用缺失的月份填充每个数组;但是我不知道怎么实现。
您可以通过类似的方式实现此目的,首先获取月份,然后修改在您的情况下为散列的数组项:
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
您还可以创建一个新的 Array
,其中 Hash
值使用默认值初始化:
data_with_default = data.map do |d|
{
name: d[:name],
data: Hash.new(0).update(d[:data])
}
end
尝试以下操作:
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] }] } }
如果 arr
是您的哈希数组,您可以分两步构建所需的数组。
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
# }
# }
# ]
有关日期格式化指令,请参阅 Enumerable#flat_map, Date::strptime, Array#minmax, Date#strftime, Array#product and Hash#merge. See also DateTime#strptime。
注意在first_month
和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"]