banditKing banditKing - 6 months ago 16
Ruby Question

Alternative to using a giant if/else in this Ruby code that assigns labels based on the time interval

I have a Ruby script that I inherited, where its reading a csv file containing "TV programs" that have a start time, and end time in this format:

start_time = 20:00:00
end_time = 20:45:00


The goal is to assign each TV program a "time-slot" (one of the following values) based on the start and end times:

23:00:00 - 05:00:00 = Late Night = l
05:00:00 - 09:00:00 = Morning = m
09:00:00 - 17:00:00 = Day Time = d
17:00:00 - 20:00:00 = Evening = e
20:00:00 - 23:00:00 = Prime = p


Right now I have a giant if/else statement that is about 100 lines of Ruby Code:

if(start_time >= 50000 && start_time < 90000) #start time is between 5 and 9 am
if(end_time <= 90000)
@timeSlot = ["Morning"]
puts "timeSlot = [Morning]"
elsif(end_time <= 170000 && end_time > 90000)
@timeSlot = ["Morning", "Daytime"]
puts "timeSlot = [Morning, Daytime]"
elsif(end_time <= 200000 && end_time > 90000 && end_time > 170000)
@timeSlot =["Morning", "Daytime", "Evening"]
puts "timeSlot =[Morning, Daytime, Evening]"
elsif(end_time <= 230000 && end_time > 90000 && end_time > 170000 && end_time > 200000)
@timeSlot =["Morning", "Daytime", "Evening", "Prime"]
puts "timeSlot =[Morning, Daytime, Evening, Prime]"
else
@timeSlot =["Morning", "Daytime", "Evening", "Prime", "LateNight"]
puts "timeSlot =[Morning, Daytime, Evening, Prime, LateNight]"
end
elsif (start_time >= 90000 && start_time < 170000)
.........
........


end


Im trying to change the implementation so the code is easy to maintain and extend and read.
My first try at this problem was to solve it visually using a matrix in excel as shown.

enter image description here

This is the problem displayed visually. Now the question is how to do this in code in an efficient way?

Any advice is welcome

Answer

One more variant...

require 'time'
RANGES = [
  ["00:00:00", "Late Night"],
  ["05:00:00", "Morning"],
  ["09:00:00", "Day Time"],
  ["17:00:00", "Evening"],
  ["20:00:00", "Prime"],
  ["23:00:00", "Late Night"]]
NBR_PERIODS = RANGES.size
LAST_PERIOD = NRB_PERIODS - 1

class Times_to_list
  def initialize
    @ranges = []
    RANGES.each {|r| @ranges << Time.strptime(r.first,"%H:%M:%S")}
  end

  def list_of_periods(start_time, end_time)  
    start_period = secs_to_period(Time.strptime(start_time, "%H:%M:%S"))
    end_period = secs_to_period(Time.strptime(end_time, "%H:%M:%S"))
    if start_time <= end_time
      text = (start_period..end_period).to_a      
    else
      text = (start_period..LAST_PERIOD).to_a + (0..end_period).to_a     
    end
    text.map {|p| p == 0 ? LAST_PERIOD : p}.uniq.sort.map {|p|
      RANGES[p].last}
  end

  private

  def secs_to_period(t) NBR_PERIODS.times {|i|
    return i if i == LAST_PERIOD or t < @ranges[i+1]} end
end

t = Times_to_list.new
p t.list_of_periods("23:48:00", "10:15:00")
  # => ["Morning", "Day Time", "Late Night"]