Skip to content

Instantly share code, notes, and snippets.

@RLGGHC
Created October 19, 2009 06:09
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 RLGGHC/4f6807eef49064027a3c to your computer and use it in GitHub Desktop.
Save RLGGHC/4f6807eef49064027a3c to your computer and use it in GitHub Desktop.
Chris Strom Solution
=begin
My solution includes comments to aid in understanding, but I should probably add an overall approach description as well.
The problem is solvable without geometry, but not quite as generalizable. Regardless, some extension to the Float and String class will be needed (to convert back and forth between time strings and floats for averaging).
== Expected output
list = %w{23:15 00:03 23:30 23:23 23:48}
average_time_of_day(list)
=> "23:35"
list = %w{06:15 07:03 06:30 06:23 06:48}
average_time_of_day(list)
=> "06:35"
== Hints
Your digital ways will not help you, time of day is cyclical.
== Note
There is a newsgroup that actually discusses this problem and offers some solutions that are very close to being complete. I'd rather not give folks hints that point them to that discussion. Like I said, it is possible to come up with a close approximation of the solution without geometry. Besides, I am somewhat hopeful that someone can surprise me by coming up with an elegant solution without geometry :)
=end
class Float
def to_time_string
hours = self.to_i
"%02d:%02d" % [hours, (self-hours)*60]
end
end
class String
# Given a time string (e.g. "23:15"), return a numeric
# representation (e.g. 23.25)
def to_time_float
hours, minutes = self.split(":")
(hours.to_i + minutes.to_f/60)
end
end
class GeometricTime
# Given a list of 24-hour times (e.g. ["23:50", "00:00", "00:00"]),
# returns the average (e.g. "00:00")
def self.average(list)
vector_sum = list.inject([0,0]) do |memo, time|
x, y = x_y_from_time(time)
[memo[0] + x, memo[1] + y]
end
time_from_x_y(*vector_sum)
end
# Convert time on a 24 hour analog clock to x-y coordinates. Align
# midnight with the x axis for easier conversion.
# * midnight => [1, 0]
# * "06:00" => [0, -1]
# * "12:00" => [-1, 0]
# * "18:00" => [0, 1]
def self.x_y_from_time(time)
# negative because angles increase counter-clockwise
radians = - 2 * Math::PI * time.to_time_float / 24
[Math.cos(radians), Math.sin(radians)]
end
# Convert from x-y coordinates back to a time string (e.g. [1, 0] =>
# "00:00"
def self.time_from_x_y(x, y)
atan2 = Math.atan2(y, x)
angle = atan2 < 0 ? atan2 + 2*Math::PI : atan2
time = ((2 * Math::PI - angle) / (2*Math::PI)) * 24
time.to_time_string
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment