Instantly share code, notes, and snippets.

# asmodis/average_time_calculator.rb Created Oct 8, 2009

What would you like to do?
Solution for RPCFN #2
 require "time" module AverageTimeCalculator SecondsPerDay = 86400 Noon = 12 #Calculates the average of the given times. #Parameter times is supposed to be an array of strings, each string with format HH:MM(am|pm) # #*Examples*: # average_time_of_day(["11:51pm", "11:56pm", "12:01am", "12:06am", "12:11am"]) # => "12:01am" # average_time_of_day(["11:51am", "11:56am", "12:01pm", "12:06pm", "12:11pm"]) # => "12:01pm" # #-- #Strategy: # Case1: All times are am (or all times are pm) # => simply calculate the average # Case2: Times are mixed # => Calculate average assuming all times are from a single day # Calculate average assuming all am times are from the following day # Choose average suiting the given times best depending on a simple metric # #The code is not suited for calculating the average delay of a flight, because it #doesn't differentiate between different days. So a flight sheduled at 10pm arriving 23h late #will be treated as a flight arriving one hour earlier. # #Other thingy: Whats the average of 12:00am and 12:00pm? # I decided to choose the earlier time (in this case 6am) #++ def average_time_of_day(times_array) #Fix a time for the (very very unlikly) case, that parsing skips midnight now = Time.now am_times, pm_times = times_array.map { |time_str| Time.parse(time_str, now) }.partition { |time| time.hour < Noon} shifted_am_times = [] unless am_times.empty? or pm_times.empty? shifted_am_times = am_times.map { |time| time + SecondsPerDay } end best_average(am_times + pm_times, pm_times + shifted_am_times).strftime("%I:%M%p").downcase end private def best_average(timeset1, timeset2) if timeset2.size < timeset1.size #shifting wasn't needed average(timeset1) else choose_best_average timeset1, timeset2 end end def choose_best_average(tset1, tset2) av1, av2 = average(tset1), average(tset2) difference(av1, tset1) <= difference(av2, tset2) ? av1 : av2 end def average(times) total = times.inject(0) do |sum, time| sum + time.to_i end Time.at(total / times.size) end def difference(time0, times) times.inject(0) { |res,time| res + (time - time0).abs } end end include AverageTimeCalculator puts average_time_of_day(["11:51pm", "11:56pm", "12:01am", "12:06am", "12:11am"]) puts average_time_of_day(["11:51am", "11:56am", "12:01pm", "12:06pm", "12:11pm"]) puts average_time_of_day(["6:41am", "6:51am", "7:01am"]) puts average_time_of_day(["12:00pm", "12:00am"])