Grouping/Sorting an Array of objects

H

Howard Roberts

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
 
P

Peña, Botp

RnJvbTogSG93YXJkIFJvYmVydHMgW21haWx0bzpob3dhcmRyb2JlcnRzQGNvbWNhc3QubmV0XSAN
CiMuLi4NCiMgQGRhdGEuc29ydHt8eCx5fCBUaW1lLnBhcnNlKHguZGF0ZSkgPD0+IFRpbWUucGFy
c2UoeS5kYXRlKX0pLmVhY2ggZG8NCiMgfGZvb3wNCiMgICBwdXRzIEZvby5kYXRlICMgU3RpbGwg
c2hvd3MgZGF0ZSBvbiBlYWNoIGxvb3AsIGJ1dCBva2F5DQojICAgcHV0cyBGb28ubmFtZQ0KIyAg
IFsuLl0NCiMgZW5kDQoNCnRyeSwNCg0KICBAZGF0YS5zb3J0X2J5e3xyZWN8IFtyZWMuZGF0ZSwg
cmVjLmNsYXNzLCByZWMubmFtZV19DQoNCm9yIHNvbWV0aGluZyBsaWtlIHRoYXQuDQoNCml0IHdv
dWxkIGJlIG5pY2UgaWYgeW91IGNhbiBwb3N0IHNvbWUgc2FtcGxlIGRhdGEgc28gd2UgY2FuIHRl
c3QgaXQgaW1tZWRpYXRlbHkuIGknbSBhIHNsb3cgdHlwaXN0IDspDQoNCg0KIyBUbyBnZXQgdGhp
bmdzIGluIGRhdGUgb3JkZXIsIGJ1dCB3aGVuIEkgY29uc2lkZXIgbWl4aW5nIGEgDQojIHNlY29u
ZCBvYmplY3QgaW50byB0aGUgYXJyYXksIHRoYXQgY29uZm91bmRzIG1hdHRlcnMgZm9yIG1lLiAN
CiMgSSBzdXNwZWN0IGdyb3VwX2J5e3xpdGVtfCBpdGVtLmNsYXNzfSBtYXkgYmUgcGFydCBvZiB0
aGUgc29sdXRpb24sIA0KIyBidXQgSSdtIG5vdCBzdXJlIGhvdz8NCg0KdGhhdCBpcyBwb3NzaWJs
ZSB0b28sIGJ1dCBsZXQgdXMgdGFrZSBpdCBvbmUgYXQgYSB0aW1lIDspDQoNCmtpbmQgcmVnYXJk
cyAtYm90cA0K
 
H

Howard Roberts

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 ;)
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
 
H

Howard Roberts

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 :)
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 :)

Thank You,
Howard
 
D

David A. Black

Hi --

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.

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 :)


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails July 21-24 Edison, NJ
* Advancing With Rails August 18-21 Edison, NJ
* Co-taught by D.A. Black and Erik Kastner
See http://www.rubypal.com for details and updates!
 
E

Erik Veenstra

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/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top