Instantly share code, notes, and snippets.

# RLGGHC/chrisstrom.rbSecret Created Oct 19, 2009

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