在这个Ruby代码中,除了使用基于时间间隔分配标签的巨型if/else之外,还有另一种选择

在这个Ruby代码中,除了使用基于时间间隔分配标签的巨型if/else之外,还有另一种选择,ruby,algorithm,data-structures,matrix,Ruby,Algorithm,Data Structures,Matrix,我继承了一个Ruby脚本,它读取一个csv文件,其中包含“电视节目”,有一个开始时间和结束时间,格式如下: start_time = 20:00:00 end_time = 20:45:00 目标是根据开始和结束时间为每个电视节目分配一个“时间段”(以下值之一): 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

我继承了一个Ruby脚本,它读取一个csv文件,其中包含“电视节目”,有一个开始时间和结束时间,格式如下:

   start_time = 20:00:00
   end_time = 20:45:00
目标是根据开始和结束时间为每个电视节目分配一个“时间段”(以下值之一):

 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
现在我有一个巨大的if/else语句,大约有100行Ruby代码:

 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
如果(开始时间>=50000和开始时间<90000)开始时间在上午5点到9点之间
如果(结束时间170000)
@时隙=[“上午”、“白天”、“晚上”]
将“时间段=[早上、白天、晚上]”
elsif(结束时间90000和结束时间>170000和结束时间>200000)
@时隙=[“上午”、“白天”、“晚上”、“黄金时段”]
将“时间段=[早上、白天、晚上、黄金时段]”
其他的
@时隙=[“上午”、“白天”、“晚上”、“黄金时段”、“深夜”]
将“时间段=[早上、白天、晚上、黄金时段、深夜]”
终止
elsif(开始时间>=90000和开始时间<170000)
.........
........
终止
我试图改变实现,使代码易于维护、扩展和阅读。 我对这个问题的第一次尝试是使用excel中的矩阵直观地解决它,如图所示

这就是直观显示的问题。现在的问题是如何在代码中以有效的方式实现这一点


欢迎提供任何建议

有几种方法可以优化代码库

  • 用下划线写数字(ruby在数字中忽略它们,但它们增强了可读性)<代码>5_00_00等于上午5点。这样更容易将小时与分钟分开
  • 您可以在
    Proc
    中为每个时隙制定条件,这为条件提供了一个可读的名称

  • 电视节目的老虎机阵列是可变的。因此,如果条件适用,我们可以添加一个匹配时间慢<代码>show.slots我将假设问题“…以有效的方式在代码中执行此操作?”是关于如何提出一个更优雅的解决方案,而不是获得一个更高效的运行时算法

    首先,我注意到嵌套的if语句包含冗余条件检查,例如

    elsif(end_time <= 200000 && end_time > 90000 && end_time > 170000)
    
    然后在if语句中使用这些变量。这将减少打字错误,可能会意外地超过50000个,等等


    希望这是朝着正确方向的有益推动。

    尽管您的业务规则很少有其他人提到的缺点,但它很有趣。下面是我如何处理它的

    require 'time'
    
    start_time = "20:00:00"
    end_time = "20:45:00"
    
    start_time = Time.strptime(start_time,"%H:%M:%S")
    end_time = Time.strptime(end_time,"%H:%M:%S")
    
    slot_times = { :late_night => {start: "23:00:00", end: "05:00:00", slot: "Late Night"},
        :morning => {start: "05:00:00", end: "09:00:00", slot: "Morning"},
        :day_time => {start: "09:00:00", end: "17:00:00", slot: "Day Time"},
        :evening => {start: "17:00:00", end: "20:00:00", slot: "Evening"},
        :prime => {start: "20:00:00", end: "23:00:00", slot: "Prime"} }
    
    slot_times.each do |k,v|  
      x,y = Time.strptime(v[:start],"%H:%M:%S"), Time.strptime(v[:end],"%H:%M:%S")
      puts v[:slot] if start_time.between?(x,y) || end_time.between?(x,y) #=> Evening, Prime
    end
    
    class Time\u Slot[:深夜、上午、白天、时间、晚上]
    
    还有一个变体

    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 = NBR_PERIODS - 1
    


    你的情况有很多冗余。例如,
    end\u time>90000和&end\u time>170000
    end\u time>170000
    相同。你没有明确你要遵守的规则。问题还不清楚。你需要确定:早晨和:白天的时间范围(明显的剪切粘贴嘘声)。您不应该使用秒而不是小时(或者修改
    间隔?
    )吗?例如,23:00开始的节目应该是深夜,而不是黄金时段和深夜。此外,我建议您按时间顺序列出标签,因此深夜打印时是最后一次(并且只打印一次)。顺便说一句,其他人,为什么在这个问题上投反对票?这在语法上是正确的,但在逻辑上是不正确的。抱歉,如果您选择开始时间=21:00:00,结束时间=04:00:00,则此操作无效。输出是基本的。它应该是程序运行的所有时间段。这对我很有效。这是最好的解决方案,因为它不需要硬编码时间段,而且它是一个单独的类,是模块化的。非常感谢!!:)这是一个优越的解决方案,因为它将策略与实施分离。这些范围甚至可以从数据库或文件中加载。
    TIME_5AM = 50000
    TIME_9AM = 90000
    ...
    
    require 'time'
    
    start_time = "20:00:00"
    end_time = "20:45:00"
    
    start_time = Time.strptime(start_time,"%H:%M:%S")
    end_time = Time.strptime(end_time,"%H:%M:%S")
    
    slot_times = { :late_night => {start: "23:00:00", end: "05:00:00", slot: "Late Night"},
        :morning => {start: "05:00:00", end: "09:00:00", slot: "Morning"},
        :day_time => {start: "09:00:00", end: "17:00:00", slot: "Day Time"},
        :evening => {start: "17:00:00", end: "20:00:00", slot: "Evening"},
        :prime => {start: "20:00:00", end: "23:00:00", slot: "Prime"} }
    
    slot_times.each do |k,v|  
      x,y = Time.strptime(v[:start],"%H:%M:%S"), Time.strptime(v[:end],"%H:%M:%S")
      puts v[:slot] if start_time.between?(x,y) || end_time.between?(x,y) #=> Evening, Prime
    end
    
    class Time_Slot < Struct.new(:name, :begin, :end)
      def overlap?(range)
        range.include?(self.begin) || range.begin.between?(self.begin, self.end)
      end
    end
    
    TIME_SLOTS = [
    Time_Slot.new(:Late_night, 0, 5),
    Time_Slot.new(:Morning, 5, 9),
    Time_Slot.new(:Day_time, 9, 17),
    Time_Slot.new(:Evening, 17, 20),
    Time_Slot.new(:Prime, 20, 23),
    Time_Slot.new(:Late_night, 23, 24)]
    
    def calc_slots(start, stop)
      range = start...stop
      TIMESLOTS.select{|ts| ts.overlap?(range)}.map(&:name)
    end
    
    p calc_slots(1,20) #=>[:Late_night, :Morning, :Day_time, :Evening]
    
    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 = NBR_PERIODS - 1
    
    class TimesToList
      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"))
        ((start_time <= end_time) ? (start_period..end_period).to_a :
          (start_period..LAST_PERIOD).to_a + (0..end_period).to_a).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
    
    TimesToList.new.list_of_periods("23:48:00", "10:15:00")
      # => ["Morning", "Day Time", "Late Night"]