Grouping/Sorting an Array of objects

Suppose I have an array of two different kinds of objects, each with
different attributes, but both having a date attribute. I’d like to be
able to loop through the array in such a manner as to be able print a
result similar to the following:

07/19/08
Foo-1 - Name
attr 1
attr 2
[…]

Foo-2 - Name
attr 1
attr 2
[…]

Bar - Name
attr 1
attr 2
[…]
07/20/08
Foo-1 - Name
attr 1
attr 2
[…]

Bar - Name
attr 1
attr 2
[…]
etc.

showing all of the Foo’s first, then the Bar’s, for each date.
If I only have Foo’s, I can easily do:

@data.sort{|x,y| Time.parse(x.date) <=> Time.parse(y.date)}).each do
|foo|
puts Foo.date # Still shows date on each loop, but okay
puts Foo.name
[…]
end

To get things in date order, but when I consider mixing a second object
into the array, that confounds matters for me. I suspect group_by{|item|
item.class} may be part of the solution, but I’m not sure how?

Any pointers would be most appreciated.

Thanks,
Howard

From: Howard R. [mailto:[email protected]]
#…

@data.sort{|x,y| Time.parse(x.date) <=> Time.parse(y.date)}).each do

|foo|

puts Foo.date # Still shows date on each loop, but okay

puts Foo.name

[…]

end

try,

@data.sort_by{|rec| [rec.date, rec.class, rec.name]}

or something like that.

it would be nice if you can post some sample data so we can test it
immediately. i’m a slow typist :wink:

To get things in date order, but when I consider mixing a

second object into the array, that confounds matters for me.

I suspect group_by{|item| item.class} may be part of the solution,

but I’m not sure how?

that is possible too, but let us take it one at a time :wink:

kind regards -botp

Peña, Botp wrote:

try,

@data.sort_by{|rec| [rec.date, rec.class, rec.name]}

or something like that.

Something like that is probably what I need, because the app doesn’t
like that line for me.

it would be nice if you can post some sample data so we can test it
immediately. i’m a slow typist :wink:
some sample data and pseudo code is here:
http://ruby.pastebin.com/m24b5e03

The output I’m trying to achieve would look like the following, listing
first the date, then the information all of the first objects , and then
all of the second objects for that date:

7/18/08

9:00 AM - Orientation
Location: Conference Room
Welcome, review agenda, and brief Q&A

7:30 AM - First Event
The Smiths invite you for a casual breakfast at Grumpy’s

7/19/08
8:00 AM - Workshop I
Location: Room 106
Boring, all day presentation by Dr. Jones

7/20/08
6:00 PM - Second Event
The Jones invite you for a Sociable Dinner at La Nepolara’s

7/21/08
8:00 AM - Workshop II
Location: Room 108
Yet another boring, all day presentation by Dr. Jones

2:30 PM - Wrap-Up
Location: Room 108
Summary, Q&A, and lots of free goodies

7:30 AM - Third Event
The Smiths invite you for a casual Breakfast at Mel’s

1:00 PM - Fourth Event
Dr. Jones and Staff invite you for a Business Lunch at The Krusty Krab

kind regards -botp
Thank you kindly for replying and a for any suggestions you might offer.

Howard

Peña, Botp wrote:

prev_date=nil
@data.sort_by do |item|
t,ampm = item.time.split
hr,min = t.split “:”
hr = “0”+hr if hr.size==1
timenew = ampm+hr+min
[item.date, timenew, item.class.to_s]
end.each do |item|

Brilliant!

There’s some clobbering of time in there since i arranged by time too :slight_smile:
I can adapt my app for that.

Is that ok?
Kind regards -botp

-botp,
This is superb! I was reluctant to ask for help on this at all because
it sounded so much like I was asking “write my code for me.” But I would
have never gotten that, because I did not know you could use sort_by in
such a way-- passing an array as the last line of the block. It is
exactly what I needed and I am most grateful-- for the clearer
understanding (and the code :slight_smile:

Thank You,
Howard

From: Howard R. [mailto:[email protected]]

some sample data and pseudo code is here:

http://ruby.pastebin.com/m24b5e03

The output I’m trying to achieve would look like the

following, listing

first the date, then the information all of the first objects

, and then

all of the second objects for that date:

7/18/08

9:00 AM - Orientation

Location: Conference Room

Welcome, review agenda, and brief Q&A

7:30 AM - First Event

The Smiths invite you for a casual breakfast at Grumpy’s

7/19/08

8:00 AM - Workshop I

Location: Room 106

Boring, all day presentation by Dr. Jones

#…

ok, that is much clearer and complete.

i just modified your last code loop as,

#—code
prev_date=nil
@data.sort_by do |item|
t,ampm = item.time.split
hr,min = t.split “:”
hr = “0”+hr if hr.size==1
timenew = ampm+hr+min
[item.date, timenew, item.class.to_s]
end.each do |item|
puts “#{item.date.strftime(‘%m/%d/%y’)}\n\n” if prev_date != item.date

if item.is_a? Meeting
puts “#{item.time} - #{item.activity}\n”
puts “Location: #{item.location}\n”
puts “#{item.description}\n\n”
else
puts “#{item.time} - #{item.name}\n”
puts “#{item.attendees} invite you for a #{item.mood}
#{item.activity} at #{item.location}\n\n”
end
prev_date = item.date
end
#—code

There’s some clobbering of time in there since i arranged by time too :slight_smile:

So the output is,

C:\family\ruby>ruby test.rb
07/18/08

7:30 AM - First event
The Smiths invite you for a casual Breakfast at Grumpy’s

9:00 AM - Orientation
Location: Conference Room
Welcome, review agenda, and brief Q&A

07/19/08

8:00 AM - Workshop I
Location: Room 106
Boring, all day presentation by Dr. Jones

07/20/08

6:00 PM - Second event
The Jones invite you for a Sociable Dinner at La Nepolara’s

07/21/08

7:30 AM - Third event
the Smiths invite you for a casual Breakfast at Mel’s

8:00 AM - Workshop II
Location: Room 108
Yet another boring, all day presentation by Dr. Jones

1:00 PM - Third event
Dr. Jones and Staff invite you for a Business Lunch at The Krusty Krab

2:30 PM - Wrap-Up
Location: Room 108
Summary, Q&A, and lots of free goodies

C:\family\ruby>

Is that ok?
Kind regards -botp

a.group_by do |o|
o.date
end.sort.each do |date, list|
p date

list.group_by do |o|
o.class
end.sort_by do |klass, _|
[Foo, Bar].index(klass) # kind_of?
end.each do |klass, list|
list.each do |o|
p o
end
end
end

gegroet,
Erik V. - http://www.erikveen.dds.nl/

Hi –

On Mon, 21 Jul 2008, Howard R. wrote:

[..]

07/20/08

To get things in date order, but when I consider mixing a second object
into the array, that confounds matters for me. I suspect group_by{|item|
item.class} may be part of the solution, but I’m not sure how?

Any pointers would be most appreciated.

Here’s a stab at it: http://pastie.org/238521. I’ve put the sorting
intelligence in the objects, and also given them to_s methods so you
don’t have to do all that formatting in the calling code (though you
can, of course, if you want a different output).

The last ten lines still seem a bit wordy to me but so be it; I have
to go get ready for work :slight_smile:

David