Search code examples
rubylogic

IF-statement inside While-loop not working


I'm wondering why the IF-statement inside the while-loop just fires once. I should get 4 joined rows but I'm just getting 2. Obviously the IF doesn't fire properly

I want basically to list the next schedules (time_tables) from a given train-number.

Thanks!

require 'date'

Time_tables =   [
    { name: '01251', start_date: '2014-04-24 22:03:00', start_location: 'A', end_date: '2014-04-24 22:10:00', end_location: 'BC' },
    { name: '05012', start_date: '2014-04-24 22:20:00', start_location: 'RI', end_date: '2014-04-24 23:10:00', end_location: 'XX' },
    { name: '03232', start_date: '2014-04-24 17:10:00', start_location: 'X', end_date: '2014-04-24 20:10:00', end_location: 'B' },
    { name: '02435', start_date: '2014-04-24 17:10:00', start_location: 'Z', end_date: '2014-04-24 20:10:00', end_location: 'B' },
    { name: '04545', start_date: '2014-04-24 22:15:00', start_location: 'BC', end_date: '2014-04-24 22:20:00', end_location: 'RI' },
    { name: '03545', start_date: '2014-04-24 23:15:00', start_location: 'XX', end_date: '2014-04-25 00:10:00', end_location: 'E' }
]

class TrainSearch
  def initialize(data)
    @data = data
  end

  def rows
    @rows ||= @data.map {|row| Row.new(row)}
  end

  # { name: '01251', start_date: '2014-04-24 22:03:00', start_location: 'A', end_date: '2014-04-24 22:10:00', end_location: 'BC' }
  def find_train(train_number)
    rows.find { |row| row.name == train_number }
  end


  def find_next_route(after_time, end_location)
    rows.find { |row| row.start_date > after_time and row.start_location == end_location }
  end

  def find_train_and_next_routes(train_number)
    if find_train(train_number)
      train = find_train(train_number)
      routes = [train] # add the train as the first route
    else
      p 'not valid number'
    end
    # we search first to see if we find a route
    # we reassign the train variable to the new train found
    #if(train = find_next_route(train.end_date, train.end_location))
    i = 0
    while i <= rows.count  do
      if(train = find_next_route(routes[-1].end_date, routes[-1].end_location))
        p 'are we in ?: '
        p i
        routes << train
      end
    i += 1
    end
    # at the end return the train and the routes
    return routes

  end



  # Do this because we need to parse the date into a time to sort
  class Row
    def initialize(row)
      @row = row
    end

    def start_date
      DateTime.parse(@row[:start_date])
    end

    def end_date
      DateTime.parse(@row[:end_date])
    end

    def name
      @row[:name]
    end

    def start_location
      @row[:start_location]
    end

    def end_location
      @row[:end_location]
    end
  end
end

user = TrainSearch.new(Time_tables)
p user.find_train_and_next_routes '01251'

Solution

  • Why are you expecting 4 routes? I am assuming you want this

    #=> [
      #<TrainSearch::Row:0x26f3c58 @row={:name=>"01251", :start_date=>"2014-04-24 22:03:00",:start_location=>"A", :end_date=>"2014-04-24 22:10:00", :end_location=>"BC"}>,
      #<TrainSearch::Row:0x26f3bf8 @row={:name=>"04545", :start_date=>"2014-04-24 22:15:00", :start_location=>"BC", :end_date=>"2014-04-24 22:20:00", :end_location=>"RI"}>, 
      #<TrainSearch::Row:0x26f3c40 @row={:name=>"05012", :start_date=>"2014-04-24 22:20:00", :start_location=>"RI", :end_date=>"2014-04-24 23:10:00", :end_location=>"XX"}>,
      #<TrainSearch::Row:0x26f3be0 @row={:name=>"03545", :start_date=>"2014-04-24 23:15:00",:start_location=>"XX", :end_date=>"2014-04-25 00:10:00", :end_location=>"E"}>]
    

    If so your issue is that

    #<TrainSearch::Row:0x26f3c40 @row={:name=>"05012", :start_date=>"2014-04-24 22:20:00", :start_location=>"RI", :end_date=>"2014-04-24 23:10:00", :end_location=>"XX"}>
    

    starts at the same time as the end_date of

    #<TrainSearch::Row:0x26f3bf8 @row={:name=>"04545", :start_date=>"2014-04-24 22:15:00", :start_location=>"BC", :end_date=>"2014-04-24 22:20:00", :end_location=>"RI"}>
    

    Thus

    def find_next_route(after_time, end_location)
        rows.find { |row| row.start_date > after_time && row.start_location == end_location }
    end
    

    returns nil because row.start_date > after_time is false adding >= will get you the desired result

    Also you can implement Row as follows

    class Row
      attr_reader :row,:start_date,:end_date,:name,:start_location,:end_location
      def initialize(row)
        @row = row
        @row.each &method(:instance_variable_set)
      end
    end