# Grouping/Sorting an Array of objects

**URL:** <https://www.ruby-forum.com/t/grouping-sorting-an-array-of-objects/143606>\
**Category:** Ruby\
**Created:** [July 21, 2008, 5:28am UTC](https://www.ruby-forum.com/t/grouping-sorting-an-array-of-objects/143606 "2008-07-21T05:28:57Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![hroberts](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/50afbb/32.png) [@hroberts](https://www.ruby-forum.com/u/hroberts)\
**Post date:** [July 21, 2008, 5:28am UTC](https://www.ruby-forum.com/t/grouping-sorting-an-array-of-objects/143606/1 "2008-07-21T05:28:57Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![hroberts](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/50afbb/32.png) [@hroberts](https://www.ruby-forum.com/u/hroberts)\
**Post date:** [July 21, 2008, 6:03am UTC](https://www.ruby-forum.com/t/grouping-sorting-an-array-of-objects/143606/2 "2008-07-21T06:03:56Z")

</div>

From: Howard R. [[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)]  
#…

# @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 😉

# 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 😉

kind regards -botp

---

<div class="post-metadata">

**Author:** ![hroberts](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/50afbb/32.png) [@hroberts](https://www.ruby-forum.com/u/hroberts)\
**Post date:** [July 21, 2008, 9:14pm UTC](https://www.ruby-forum.com/t/grouping-sorting-an-array-of-objects/143606/3 "2008-07-21T21:14:34Z")

</div>

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 😉  
> some sample data and pseudo code is here:  
> [http://ruby.pastebin.com/m24b5e03](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

---

<div class="post-metadata">

**Author:** ![hroberts](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/50afbb/32.png) [@hroberts](https://www.ruby-forum.com/u/hroberts)\
**Post date:** [July 22, 2008, 12:37pm UTC](https://www.ruby-forum.com/t/grouping-sorting-an-array-of-objects/143606/4 "2008-07-22T12:37:21Z")

</div>

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 🙂  
> 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

---

<div class="post-metadata">

**Author:** ![hroberts](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/50afbb/32.png) [@hroberts](https://www.ruby-forum.com/u/hroberts)\
**Post date:** [July 22, 2008, 5:23am UTC](https://www.ruby-forum.com/t/grouping-sorting-an-array-of-objects/143606/5 "2008-07-22T05:23:11Z")

</div>

From: Howard R. [[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)]

# some sample data and pseudo code is here:

# [http://ruby.pastebin.com/m24b5e03](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 🙂

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

---

<div class="post-metadata">

**Author:** ![hroberts](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/50afbb/32.png) [@hroberts](https://www.ruby-forum.com/u/hroberts)\
**Post date:** [July 22, 2008, 5:02pm UTC](https://www.ruby-forum.com/t/grouping-sorting-an-array-of-objects/143606/6 "2008-07-22T17:02:43Z")

</div>

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/](http://www.erikveen.dds.nl/)

---

<div class="post-metadata">

**Author:** ![hroberts](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/50afbb/32.png) [@hroberts](https://www.ruby-forum.com/u/hroberts)\
**Post date:** [July 22, 2008, 1:28pm UTC](https://www.ruby-forum.com/t/grouping-sorting-an-array-of-objects/143606/7 "2008-07-22T13:28:21Z")

</div>

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](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
