patternrubyMinor
Ensure continuous date range
Viewed 0 times
rangedateensurecontinuous
Problem
I have two arrays
which represent dates and a view count. To display them in a graph, I also need the values between the dates, which are 0:
I came up with a fairly complicated solution:
I think thats not a good solution. Any ideas on how to improve the code? Or a completely different approach?
dates = ["20161010","20161013"]
values = [5,3]which represent dates and a view count. To display them in a graph, I also need the values between the dates, which are 0:
["20161010","20161011","20161012","20161013"]
[5,0,0,3]I came up with a fairly complicated solution:
dates = ["20161010","20161013"]
values = [5,3]
first_date = Date.new(Integer(dates.first[0..3]), Integer(dates.first[4..5]), Integer(dates.first[6..7]))
last_date = Date.new(Integer(dates.last[0..3]), Integer(dates.last[4..5]), Integer(dates.last[6..7]))
# create a continous range
range = (first_date..last_date).to_a.map {|d| d.strftime("%Y%m%d")}
# store the indexes of the original dates inside the new range
date_idxs = dates.map {|d| range.index(d) }
# create a zero filled array with length of our range
filled_values = Array.new(range.length, 0)
values.each_with_index do |value,idx|
idx_in_filled_values = date_idxs[idx]
filled_values[idx_in_filled_values] = value
end
puts range # ["20161010", "20161011", "20161012", "20161013"]
puts filled_values # [5, 0, 0, 3]I think thats not a good solution. Any ideas on how to improve the code? Or a completely different approach?
Solution
Several aspects of your code could use improvement:
-
I recommend
-
Instead, you should make a
Here is one solution:
- It would be nice if the code were packaged in a function.
-
Date.new(Integer(dates.first[0..3]), Integer(dates.first[4..5]), Integer(dates.first[6..7])) is rather verbose and ugly.I recommend
DateTime.strptime for date parsing — it's the inverse of strftime.- You can call
Range#mapdirectly; you don't need to doto_afirst.
-
dates.map { |d| range.index(d) } could be problematic for performance, since it is O(n2).Instead, you should make a
Hash.Here is one solution:
require 'date_core'
DATE_FMT = '%Y%m%d'
def filled_date_series(dates, values, default_value=0)
data = Hash[dates.zip(values)]
datetime_range = (DateTime.strptime(dates.first, DATE_FMT) ..
DateTime.strptime(dates.last, DATE_FMT))
date_range = datetime_range.map { |dt| dt.strftime(DATE_FMT) }
[
date_range,
date_range.map { |d| data[d] || default_value }
]
end
dates = ["20161010", "20161013"]
values = [5, 3]
range, filled_values = filled_date_series(dates, values)Code Snippets
require 'date_core'
DATE_FMT = '%Y%m%d'
def filled_date_series(dates, values, default_value=0)
data = Hash[dates.zip(values)]
datetime_range = (DateTime.strptime(dates.first, DATE_FMT) ..
DateTime.strptime(dates.last, DATE_FMT))
date_range = datetime_range.map { |dt| dt.strftime(DATE_FMT) }
[
date_range,
date_range.map { |d| data[d] || default_value }
]
end
dates = ["20161010", "20161013"]
values = [5, 3]
range, filled_values = filled_date_series(dates, values)Context
StackExchange Code Review Q#147226, answer score: 3
Revisions (0)
No revisions yet.