secret
Last active

refactored based on challenge feedback (unit test, inject, and strfmtime)

  • Download Gist
tomv.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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
# 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

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.