Oct 20 2009

My solution to RPCFN 2

Category: bdd,rubygiordano scalzo @ 2:22 pm

The solutions for RPCFN 2 are now under judgement, so it’s the time to show my effort.

The problem was easy, but a little tricky: given a list of time of day, the program should find the average time.
The tricky part was to manage “am” and “pm” times, mapping them in date format: given “11:59am” and “12:00am”, then average time should be midnight.

My solution is based on the principle than if the range between “am” and “pm” times is under half a day, they are in the same day, otherwise a day leap occurs; this approach worked well, althought it needed a little bit of explanation in code, as noted by Chris himself ;-) .

These are my spec:

$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
require 'average_time_of_day'

describe 'average_time_of_day' do
	context 'for "06:00pm" and "07:00pm"' do
		it 'should be "06:30pm"' do
			avg = average_time_of_day(["06:00pm", "07:00pm"])
			avg.should == "06:30pm"
		end
	end
	context 'for "06:00pm", "07:00pm" and "08:00pm' do
		it 'should be "07:00pm"' do
			avg = average_time_of_day(["06:00pm", "07:00pm", "08:00pm"])
			avg.should == "07:00pm"
		end
	end
	context 'for "06:41am", "06:51am" and "07:01am' do
		it 'should be "06:51am"' do
			avg = average_time_of_day(["06:41am", "06:51am", "07:01am"])
			avg.should == "06:51am"
		end
	end

	context 'for "23:59pm" and "12:01am' do
		it 'should be "12:00am"' do
			avg = average_time_of_day(["23:59pm", "00:01am"])
			avg.should == "12:00am"
		end
	end

	context 'for "11:51pm", "11:56pm", "12:01am", "12:06am" and  "12:11am"' do
		it 'should be "12:01am"' do
			avg = average_time_of_day(["11:51pm", "11:56pm", "12:01am", "12:06am", "12:11am"])
			avg.should == "12:01am"
		end
	end

	context 'for "11:15pm", "12:03am", "11:30pm", "11:23pm", "11:48pm"' do
		it 'should be "11:35pm"' do
			avg = average_time_of_day(["11:15pm", "12:03am", "11:30pm", "11:23pm", "11:48pm"])
			avg.should == "11:35pm"
		end
	end

	context 'for "05:15am", "06:03am", "05:30am", "05:23am", "05:48am"' do
		it 'should be "05:35am"' do
			avg = average_time_of_day(["05:15am", "06:03am", "05:30am", "05:23am", "05:48am"])
			avg.should == "05:35am"
		end
	end

	context 'for "11:15am", "12:03pm", "11:30am", "11:23am", "11:48am"' do
		it 'should be "11:35am"' do
			avg = average_time_of_day(["11:15am", "12:03pm", "11:30am", "11:23am", "11:48am"])
			avg.should == "11:35am"
		end
	end

	context 'for "6:00pm" and "6:00am' do
		it 'should be "12:00am"' do
			avg = average_time_of_day(["6:00pm", "6:00am"])
			avg.should == "12:00am"
		end
	end

	context 'for "12:01am", "11:51pm", "11:56pm",  "12:06am" and  "12:11am"' do
		it 'should be "12:01am"' do
			avg = average_time_of_day(["12:01am", "11:51pm", "11:56pm", "12:06am", "12:11am"])
			avg.should == "12:01am"
		end
	end

end

and this are my code:

require 'time'

private
class Array
	def to_sec
		map {|t|t.to_f}
	end

	def avg
		(size > 0) ? to_sec.inject(0.0){|sum,el| sum + el}/size : 0

	end
end

class Time
	def am?
		hour < 12
	end

	def pm?
		not am?
	end

	def to_s
		strftime("%I:%M%p").downcase
	end

end

DAY_IN_SEC = 24*60*60

def adjust_order_for(times)
	to_adjust?(times) ? adjusted(times) : times
end

def to_adjust?(times)
	avg_am = times.select { |t| t.am? }.avg
	avg_pm = times.select { |t| t.pm? }.avg
	avg_pm - avg_am  >= DAY_IN_SEC/2
end

def adjusted(times)
	times.map { |t|(t.am? ? t+DAY_IN_SEC : t) }
end

public
def average_time_of_day(times)
	times = adjust_order_for(times.map { |t| Time.parse(t) })

	Time.at(times.avg).to_s
end

Next Quiz is scheduled for 1st Nov. 2009, and will be provided by Gautam Rege.

Technorati Tags: ,

Tags: ,

  • http://xplayer.wordpress.com Pietro Di Bello

    It seems to me that a spec is incorrect, since 23:59pm doesn’t make sense to me (even if I guess this test is still green).

    context 'for "23:59pm" and "12:01am' do
      it 'should be "12:00am"' do
        avg = average_time_of_day(["23:59pm", "00:01am"])
        avg.should == "12:00am"
      end
    end
    

    anyway, good job!

  • http://giordano.scalzo.biz giordano scalzo

    woops!
    the correct one is

    	context 'for "11:59pm" and "12:01am' do
    		it 'should be "12:00am"' do
    			avg = average_time_of_day(["11:59pm", "00:01am"])
    			avg.should == "12:00am"
    		end
    	end
    

    I misread this comment http://rubylearning.com/blog/2009/10/08/rpcfn-average-arrival-time-for-a-flight-2/comment-page-1/#comment-119541.

    thanx to point it out.