我有一个数组,其中每个数组项都是一个带日期值的哈希,如下面的例子所示。实际上,它更长,每个项目大约有20个日期而不是3.我需要做的是获取每个项目的日期间隔值(即每个日期值之间的天数)和它们的间隔中位数。我的代码如下:
require 'csv'
require 'date'
dateArray = [{:date_one => "May 1", :date_two =>"May 5", :date_three => " "}, {:date_one => "May 10", :date_two =>"May 10", :date_three => "May 20"}, {:date_one => "May 6", :date_two =>"May 11", :date_three => "May 12"}]
public
def median
sorted = self.sort
len = sorted.length
return (sorted[(len - 1) / 2] + sorted[len / 2]) / 2.0
end
puts dateIntervals = dateArray.map{|h| (DateTime.parse(h[:date_two]) - DateTime.parse(h[:date_one])).to_i}
puts "\nMedian: "
puts dateIntervals.median
返回这些日期间隔值和此中位数:
4
0
5
Median: 4
但是,其中一些项的值为空,如第一项中的:date_three
值。如果我尝试为:date_three
到:date_two values
运行相同的等式,如下所示,它将引发错误,因为最后:date_three
值为空。
我可以无法获得该间隔,但我仍然需要接下来的两个项目日期间隔(分别为10和1)。
当我尝试运行它们时,如何跳过返回错误的间隔?
答案 0 :(得分:1)
我建议添加可以处理您期望的输入类型的辅助函数。例如:
def date_diff(date_one, date_two)
return nil if date_one.nil? || date_two.nil?
(date_one - date_two).to_i
end
def str_to_date(input_string)
DateTime.parse(input_string)
rescue
nil
end
dateArray.map{|h| date_diff(str_to_date(h[:date_three]), str_to_date(h[:date_two])) }
=> [nil, 10, 1]
dateArray.map{|h| date_diff(str_to_date(h[:date_three]), str_to_date(h[:date_two])) }.compact.median
=> 5.5
这里的奖励是你可以为各个组件添加单元测试,这样你就可以轻松测试边缘情况(零日期,空字符串日期等)。
答案 1 :(得分:0)
在地图块中,您只需添加一项检查,以确保值不是空白
dateIntervals = dateArray.map{ |h|
(DateTime.parse(h[:date_two]) - DateTime.parse(h[:date_one])).to_i unless any_blank?(h)
}
def any_blank?(h)
h.each do |k, v|
return true if v == " "
end
end
答案 2 :(得分:0)
我首先要过滤掉空值(我检查字符串是否完全由空格组成或为空),然后使用现有代码比较剩余的值。我添加了一个循环,它将序列中的所有值与下一个值进行比较。
dateArray = [
{ date_one: "May 1", date_two: "May 5", date_three: " ", date_four: "" },
{ date_one: "May 10", date_two: "May 10", date_three: "May 20" }
]
intervals = dateArray.map do |hash|
filtered = hash.values.reject { |str| str =~ /^\s*$/ }
(0...filtered.size-1).map { |idx| (DateTime.parse(filtered[idx+1]) - DateTime.parse(filtered[idx])).to_i }
end
# => [[4], [0, 10]]