Skip to content

Instantly share code, notes, and snippets.

@TomV

TomV/tomv.rb Secret

Created October 9, 2009 22:48
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 TomV/6da8bd7345d7ed7a6040 to your computer and use it in GitHub Desktop.
Save TomV/6da8bd7345d7ed7a6040 to your computer and use it in GitHub Desktop.
refactored based on challenge feedback (unit test, inject, and strfmtime)
# Ruby Programming Challenge For Newbies, (#2)
# Author: tomv
#
# Calculate the average time of day from several times in the format
# [ '12:11am', '11:51pm','11:56pm','12:01am', '12:06am']
# returns the average time in string format
# => '12:01am'
# My approach was to get the average difference between each of the
# times, compared to the first time in the list.
# Then add the average difference in time to the base time to get an average.
# The trick was to figure out how to minimize the differences by moving the day around
# since for the edge cases, the next day (12:01 pm) or the previous day (11:55am)
# might yeild a smaller difference that the same time on the same day.
# Would be easy to extend this to get a standard deviation of the time differences, so you could
# Likely arrival is "12:30pm +/- 12 minutes in most cases, or something.
#
# I included a simple set of tests as an additional function: test_average_time_of_day()
# that runs through a few test cases.
# Note that the results for average_time_of_day(['12am', '12pm']) could be either '6pm' or '6am'
require 'time'
# To run in irb
# >load 'tomv.rb'
# >average_time_of_day([ '12:11am', '11:51pm','11:56pm','12:01am', '12:06am'])
# => "12:01am"
def average_time_of_day(times)
total = 0.0
base_time = Time.parse(times[0]) #take the first time, and use as a 'base' then calculate avg. difference.
times.each do |t|
simple_time = Time.parse(t) # Time.parse assumes current day when parsing
d1 = base_time - simple_time # Get the time difference between base and current item's time for same day
prev_next = (base_time.hour > 12)? 1:-1 # Get diff between base and next or prev day.(next day for pm, prev day for am times)
d2 = base_time - (simple_time + 86400*prev_next) # use next day time
diff = (d1.abs < d2.abs)? d1: d2 # select the smallest difference
total += diff # running total of differences used for calc. avg. difference from base.
end
# calcuate average time by adding avg. difference of times to the base time, then format
(base_time - (total/times.size)).strftime('%l:%M%P')
end
# Simple test of function
# Run the function through it's paces with a few simple tests
def test_average_time_of_day
test=[]
test[0] = {
:description => 'Initial Challenge Example',
:input_times => [ '12:11am', '11:51pm','11:56pm','12:01am', '12:06am'],
:correct_answer => '12:01am'
}
test[1] = {
:description => 'Additional provided example',
:input_times => ['6:41am','6:51am','7:01am'],
:correct_answer => '6:51am'
}
test[2] = {
:description => 'Edge case: 12am and 12pm (6am or 6pm are correct)',
:input_times => ['12am','12pm'],
:correct_answer => '6:00pm'
}
test[3] = {
:description => 'Edge case: times around noon time ( AM to PM)',
:input_times => ['11:45am','12:15pm','11:50am', '12:10pm' ],
:correct_answer => '12:00pm'
}
test[4] = {
:description => 'Simple case with several entries',
:input_times => ['7:15am','7:30am', '7:45am', '7:30am', '7:30am', '7:45am','7:15am'],
:correct_answer => '7:30am'
}
test.each do |item|
puts "Test: #{item[:description]} "
puts "Input times: #{item[:input_times].inspect}"
puts "Expected: #{item[:correct_answer]}"
puts "Got: #{average_time_of_day(item[:input_times])}"
success = average_time_of_day(item[:input_times]).strip == item[:correct_answer].strip
if success
puts '=========== PASSED =============='
else
puts '########### FAILED ##############'
end
puts '---------------------------------------------'
end
puts "All Done"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment