Skip to content

Instantly share code, notes, and snippets.

@asmodis
Created October 8, 2009 21:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save asmodis/205429 to your computer and use it in GitHub Desktop.
Save asmodis/205429 to your computer and use it in GitHub Desktop.
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"])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment