[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Reopening Classes

anthony.green@bbc.co.uk

10/25/2006 12:41:00 PM


Can someone offer an explaination as to what I'm encountering here..

.......................................................................................
This code doesn't work...

class Time
def <=>(other_time)
self.strftime("%H%M%S%Y%m%d").to_i <=>
other_time.strftime("%H%M%S%Y%m%d").to_i
end
end

first = Time.local(2006, 10, 21)
last = Time.local(2006, 10, 27)

time_slots = []
range = first..last
range.step(1.hour) do |day_slot|
time_slots << day_slot
end

time_slots.sort

.......................................................................................

the time_slots array isn't populating properly
.......................................................................................

This does

first = Time.local(2006, 10, 21)
last = Time.local(2006, 10, 27)

time_slots = []
range = first..last
range.step(1.hour) do |day_slot|
time_slots << day_slot
end

class Time
def <=>(other_time)
self.strftime("%H%M%S%Y%m%d").to_i <=>
other_time.strftime("%H%M%S%Y%m%d").to_i
end
end

time_slots.sort

.......................................................................................

Tony

7 Answers

Paul Battley

10/25/2006 12:59:00 PM

0

On 25/10/06, anthony.green@bbc.co.uk <anthony.green@bbc.co.uk> wrote:
>
> Can someone offer an explaination as to what I'm encountering here..

Range#each employs <=>, so by changing the semantics of the
comparison, you break your step loop. When you redefine <=> after the
loop, it doesn't affect it, so your second example works.

Instead of altering Time, you could just do this:

time_slots.sort_by{ |ts| ts.strftime("%H%M%S%Y%m%d").to_i }

Paul.

Ara.T.Howard

10/25/2006 2:04:00 PM

0

Rick DeNatale

10/25/2006 3:07:00 PM

0

On 10/25/06, Paul Battley <pbattley@gmail.com> wrote:
> On 25/10/06, anthony.green@bbc.co.uk <anthony.green@bbc.co.uk> wrote:
> >
> > Can someone offer an explaination as to what I'm encountering here..
>
> Range#each employs <=>, so by changing the semantics of the
> comparison, you break your step loop. When you redefine <=> after the
> loop, it doesn't affect it, so your second example works.
>
> Instead of altering Time, you could just do this:
>
> time_slots.sort_by{ |ts| ts.strftime("%H%M%S%Y%m%d").to_i }

Another observation.

Building a range of times and then using step to obtain each hour is
pretty inefficient.

Range#step basically works like this I might have an off by one bug
but it gets the idea across:

class Range
def step(incr = 1)
elt = self.begin
end = self.end
ctr = 0
while ((elt <=> end)
if (ctr == 0)
yield elt
ctr = incr
end
elt = elt.succ
ctr -= 1
end
end

And Time#succ gives the time one second later than the receiver.

So the while look is going to be executed once for every second in the
range, in this case 6 days * 24 hours * 60 minutes * 60 seconds, so to
get
the 144 Time objects actually needed, a total of 518400 will be allocated.


This costs time and memory, and GC cycles, which may or may not be important.

Another way to compute timeslots which avoids this might be:

timeslots = (0..6*24).map {|h| first + h.hour}

Generalizing this to arbitray start and end times is left as an
exercise to the reader.


--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denh...

anthony.green@bbc.co.uk

10/25/2006 5:42:00 PM

0


> Another way to compute timeslots which avoids this might be:
>
> timeslots = (0..6*24).map {|h| first + h.hour}
>
> Generalizing this to arbitray start and end times is left as an
> exercise to the reader.


Something like this ?

# add a to date method for Time class

class Time
def to_date
Date.new(year, month, day)
rescue NameError
nil
end
end

# first date and last date

first = Time.local(2006, 10, 21, 0, 0, 0)
last = Time.local(2006, 10, 28, 0, 0, 0)

# calculate the number of days between them

range = last.to_date - first.to_date

# create your array

timeslots = (0..range*24).map {|h| first + h.hour}

# remove the last one as it'll be the first time slot of the next day

@timeslots = timeslots[0, timeslots.size - 1]

# sort by timeslot then by day

@timeslots.sort! {|a, b| a.strftime("%H%M%S%Y%m%d").to_i <=>
b.strftime("%H%M%S%Y%m%d").to_i}

Tony

Ken Bloom

10/25/2006 6:06:00 PM

0

On Wed, 25 Oct 2006 05:40:51 -0700, "anthony.green wrote:

> Can someone offer an explaination as to what I'm encountering here..
>
> ......................................................................................
> This code doesn't work...
>
> class Time
> def <=>(other_time)
> self.strftime("%H%M%S%Y%m%d").to_i <=>
> other_time.strftime("%H%M%S%Y%m%d").to_i
> end
> end
>
> first = Time.local(2006, 10, 21)
> last = Time.local(2006, 10, 27)
>
> time_slots = []
> range = first..last
> range.step(1.hour) do |day_slot|
> time_slots << day_slot
> end
>
> time_slots.sort
>
> ......................................................................................
>
> the time_slots array isn't populating properly
> ......................................................................................
>
> This does
>
> first = Time.local(2006, 10, 21)
> last = Time.local(2006, 10, 27)
>
> time_slots = []
> range = first..last
> range.step(1.hour) do |day_slot|
> time_slots << day_slot
> end
>
> class Time
> def <=>(other_time)
> self.strftime("%H%M%S%Y%m%d").to_i <=>
> other_time.strftime("%H%M%S%Y%m%d").to_i
> end
> end
>
> time_slots.sort

You can use a custom comparison function by passing a block to sort, so
there's no reason to override the spaceship operator (that is, the <=>
operator).

You could use time_slots.sort {|x,y| x.strftime("%H%M%S%Y%m%d").to_i <=> y.strftime("%H%M%S%Y%m%d").to_i}

It's probably more efficient to use sort_by, as that only computes each
strftime once:

time_slots.sort_by{|x| x.strftime("%H%M%S%Y%m%d").to_i }

--Ken

--
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu...
I've added a signing subkey to my GPG key. Please update your keyring.

anthony.green@bbc.co.uk

10/26/2006 5:20:00 PM

0


> Another way to compute timeslots which avoids this might be:
>
> timeslots = (0..6*24).map {|h| first + h.hour}
>
> Generalizing this to arbitray start and end times is left as an
> exercise to the reader.

Maybe this ? so you represent day segments

start_time = Time.gm(2006, 10, 31, 0, 0, 0)
slots = 3
no_of_days = 3

schedule =[]
timeslots = (0..slots).map{|h| start_time + h.hour}
timeslots.each do |timeslot|
(0..no_of_days).map do |i|
schedule << timeslot+i.day
end
end
puts schedule

Tony

Ara.T.Howard

10/26/2006 5:35:00 PM

0