public
Last active

Solution for RPCFN #2

  • Download Gist
average_time_calculator.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
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"])

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.