From: ml.morus.walter@... (Morus Walter) Date: 2006-08-28T05:25:08+09:00 Subject: Re: [QUIZ] [SOLUTION] DayRange (#92) In article <20060825130122.XQZJ22014.centrmmtao02.cox.net@eastrmimpo01.cox.net>, Ruby Quiz writes: one remark: I don't like the suggested interface (though I used and didn't work out an alternative). It does not seem reasonable to instanciate an object providing all the information in the constructor and the only thing one can do with that object is call one method once (multiple calls to to_s should be avoided for performance). Of course one could extend that api providing additional means that justify the use of a class, but as is, it does not make sense to me. A simple function (probably packed into a module for namespace reasons) would do the job just as good. Or do I miss something? I just added this remark since the quiz explicitly asks for �the best "Ruby way"�. My solutions takes a list of days which may be grouped to a list of arrays. Duplicate entries are removed. The to_s method provides an optional parameter to output full day names. #! /usr/bin/ruby class Array # split array into array of contiguous slices # a slice is contiguous if each item value is the successor of the # value of the previous item def split_contiguous() self.inject( [ [] ] ) do | list, item | list[-1].empty? || list[-1][-1].succ == item ? list[-1] << item : list << [ item ] list end end end class DayRange # define weekday names as constants @@WEEKDAY = [ nil, 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ] @@FULLWEEKDAY = [ nil, 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ] # prepare for fast weekday to day of week resolution @@DAYOFWEEK = {} @@WEEKDAY[1,7].each_with_index { | day,idx | @@DAYOFWEEK[day] = idx + 1 } @@FULLWEEKDAY[1,7].each_with_index { | day,idx | @@DAYOFWEEK[day] = idx + 1 } # take a list of objects or arrays of objects and convert them to an # unique sorted array of day of week numbers def initialize( *days ) @days = days.flatten.collect do | day0 | day = @@DAYOFWEEK[day0] || day0.to_i # allow for non integer input raise ArgumentError.new(day0.inspect) if day < 1 or day > 7 # check input day end.sort.uniq end # provide a list of weekdays or weekday ranges def day_range( full = false ) weekday = full ? @@FULLWEEKDAY : @@WEEKDAY @days.split_contiguous.inject( [] ) do | list, range | list << ( range.size <= 2 ? weekday[range[0]] : weekday[range[0]] + '-' + weekday[range[-1]] ) list << weekday[range[1]] if range.size == 2 list end end def to_s( full = false ) day_range(full).join(', ') end end puts DayRange.new( 1,'Tue',3,4,5,6,7 ).to_s(true) puts DayRange.new(1,2,3,4,5,6,7) puts DayRange.new(1,2,3,6,7) puts DayRange.new(1,3,4,5,6) puts DayRange.new(2,3,4,6,7) puts DayRange.new(1,3,4,6,7) puts DayRange.new(7) puts DayRange.new(1,7) puts DayRange.new(1,8)