# Reopening Classes

**URL:** <https://www.ruby-forum.com/t/reopening-classes/73582>\
**Category:** Ruby\
**Created:** [October 25, 2006, 2:47pm UTC](https://www.ruby-forum.com/t/reopening-classes/73582 "2006-10-25T14:47:22Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [October 25, 2006, 2:47pm UTC](https://www.ruby-forum.com/t/reopening-classes/73582/1 "2006-10-25T14:47:22Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [October 25, 2006, 3:01pm UTC](https://www.ruby-forum.com/t/reopening-classes/73582/2 "2006-10-25T15:01:24Z")

</div>

On 25/10/06, removed\_email\_address@domain.invalid [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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.

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [October 25, 2006, 4:09pm UTC](https://www.ruby-forum.com/t/reopening-classes/73582/3 "2006-10-25T16:09:36Z")

</div>

On Wed, 25 Oct 2006, removed\_email\_address@domain.invalid wrote:

> end  
> time\_slots.sort
> 
> end  
> end
> 
> time\_slots.sort
> 
> …

i see you already got an answer, but you might want to know about this  
idiom:

harp:~ \> cat a.rb  
lt = lambda{|\*a| Time.local \*a}  
hr = 3600  
times = []  
fields = %w( hour min sec year month day )

( lt[2006, 10, 21] … lt[2006, 10, 23] ).step(hr){|t| times \<\< t}

sorted = times.sort\_by{|t| fields.map{|f| t.send f}}

puts sorted.first(16)

harp:~ \> ruby a.rb  
Sat Oct 21 00:00:00 MDT 2006  
Sun Oct 22 00:00:00 MDT 2006  
Mon Oct 23 00:00:00 MDT 2006  
Sat Oct 21 01:00:00 MDT 2006  
Sun Oct 22 01:00:00 MDT 2006  
Sat Oct 21 02:00:00 MDT 2006  
Sun Oct 22 02:00:00 MDT 2006  
Sat Oct 21 03:00:00 MDT 2006  
Sun Oct 22 03:00:00 MDT 2006  
Sat Oct 21 04:00:00 MDT 2006  
Sun Oct 22 04:00:00 MDT 2006  
Sat Oct 21 05:00:00 MDT 2006  
Sun Oct 22 05:00:00 MDT 2006  
Sat Oct 21 06:00:00 MDT 2006  
Sun Oct 22 06:00:00 MDT 2006  
Sat Oct 21 07:00:00 MDT 2006

the basic idea of

fields = %w( one two three )

list.sort\_by{|elem| fields.map{|f| elem.send f}}

is powerful.

regards.

-a

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [October 25, 2006, 7:46pm UTC](https://www.ruby-forum.com/t/reopening-classes/73582/4 "2006-10-25T19:46:22Z")

</div>

> 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

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [October 25, 2006, 5:07pm UTC](https://www.ruby-forum.com/t/reopening-classes/73582/5 "2006-10-25T17:07:50Z")

</div>

On 10/25/06, Paul B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> 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.denhaven2.com/](http://talklikeaduck.denhaven2.com/)

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [October 26, 2006, 7:26pm UTC](https://www.ruby-forum.com/t/reopening-classes/73582/6 "2006-10-26T19:26:27Z")

</div>

> 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

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [October 25, 2006, 8:10pm UTC](https://www.ruby-forum.com/t/reopening-classes/73582/7 "2006-10-25T20:10:24Z")

</div>

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

> end  
> time\_slots.sort
> 
> 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

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [October 26, 2006, 7:36pm UTC](https://www.ruby-forum.com/t/reopening-classes/73582/8 "2006-10-26T19:36:30Z")

</div>

On Fri, 27 Oct 2006, removed\_email\_address@domain.invalid wrote:

> slots = 3
> 
> Tony

[http://runt.rubyforge.org/](http://runt.rubyforge.org/)

-a

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [October 26, 2006, 11:24pm UTC](https://www.ruby-forum.com/t/reopening-classes/73582/9 "2006-10-26T23:24:56Z")

</div>

On 10/26/06, removed\_email\_address@domain.invalid [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > Maybe this ? so you represent day segments  
> > end  
> > end  
> > puts schedule
> > 
> > Tony
> 
> [http://runt.rubyforge.org/](http://runt.rubyforge.org/)

I remember very well when someone bashed me because I reported a broken  
link, I am still wondering why, anyway  
Ara is the link ok, I can go to rubyforge but not to runt, or was that  
“rant” 😉  
R.

-a

> –  
> my religion is very simple. my religion is kindness. – the dalai lama

–  
The reasonable man adapts himself to the world; the unreasonable one  
persists in trying to adapt the world to himself. Therefore all progress  
depends on the unreasonable man.

- George Bernard Shaw
