Sorting by two fields

I have a list of TimeSheet objects from an ealier AR query, which I
can sort by the full name of the user like so:

@time_sheet_entries.sort! { |a,b| a.user.full_name <=> b.user.full_name
}

I can sort by the started time like so:

@time_sheet_entries.sort! { |a,b| a.start_time <=> b.start_time }

My question is how do I do a sort so that the list is sorted primarily
by user.full_name but also by start_time? So that all the records for
Joe Blogs are together but within those rather than being random it is
then ordered by start_time?

I know I could do it by putting some SQL on the original AR query but
I’d like to know how to do it without doing that.

FYI what is happening is:

@time_sheet_entries.sort
foreach entry in @time_sheet_entries
… print out that line in a table
end

I know that

@time_sheet_entries.sort!{ |a,b| a.user.full_name <=> b.full_name
}.sort!{ |a,b| a.start_time <=> b.start_time }

won’t do the trick because assuming it is even valid Ruby it would
just end up sorting by start_time. I thought that I could get a list
of the users then do a foreach loop just picking up the users then
iterating over them… (pseudo code so don’t expect this to actually
work…)

@time_sheet_entries.sort
foreach user in @time_sheet_entries.unique(|x| x.user}
foreach entry in @time_sheet_entries.select(|x| x.user = user}
… print out that line in a table
end
end

but I think that’s quite lame. Surely there is a way to do it in one
line? Any ideas anyone ? :stuck_out_tongue:

-Rob


“On two occasions, I have been asked [by members of Parliament],
‘Pray, Mr. Babbage, if you put into the machine wrong figures, will
the right answers come out?’ I am not able to rightly apprehend the
kind of confusion of ideas that could provoke such a question.”
– Charles Babbage (1791-1871)

“98.5% of DNA is considered to be junk DNA with no known purpose.
Maybe it’s XML tags.” – Anon

http://www.robhulme.com/
http://robhu.livejournal.com/

On 7/26/06, Robert H. [email protected] wrote:

My question is how do I do a sort so that the list is sorted primarily
foreach entry in @time_sheet_entries
of the users then do a foreach loop just picking up the users then

– Charles Babbage (1791-1871)

You could sort it when you get it from the database.

:order => ‘field1, field2’

Alternatively, a pretty convoluted method

tmp = @time_sheet_entries.group_by {&:full_name}

@time_sheet_entries = tmp.keys.inject([]) do |arry, key|
arry << tmp[key].sort_by{&:start_date}
end

On Tuesday, July 25, 2006, at 5:48 PM, Robert H. wrote:

by user.full_name but also by start_time? So that all the records for
… print out that line in a table
iterating over them… (pseudo code so don’t expect this to actually
but I think that’s quite lame. Surely there is a way to do it in one

“98.5% of DNA is considered to be junk DNA with no known purpose.
Maybe it’s XML tags.” – Anon

http://www.robhulme.com/
http://robhu.livejournal.com/


Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

@time_sheet_entries.sort! do |a,b|
n = a.user.full_name <=> b.user.full_name
n == 0 ? a.start_time <=> b.start_time : n
end

The basic idea here is that the block for sort! should return a -1, 0,
or 1 for the comparison. Just write code in there that will do that for
the particular sort you want to do. In this case, if the names are
equal, it compares the start_times.

@time_sheet_entries = @time_sheet_entries.sort_by {|x|
“#{x.user.full_name} #{x.start_time.to_i}” }

This may also work. The key here is to add the second field in such a
way that it sorts properly when displayed as a string. In this case, we
just convert it to a numerical timestamp.

To sort in decending time order, you could do this…

@time_sheet_entries = @time_sheet_entries.sort_by {|x|
“#{x.user.full_name} #{(Time.now - x.start_time).to_i}” }

Warning: Untested YMMV.

_Kevin
www.sciwerks.com

@time_sheet_entries.sort! do |a,b|
n = a.user.full_name <=> b.user.full_name
n == 0 ? a.start_time <=> b.start_time : n
end
That’s brilliant :slight_smile: Thanks a lot. It works and more importantly makes
sense to me when I read it :slight_smile:

@time_sheet_entries = @time_sheet_entries.sort_by {|x|
“#{x.user.full_name} #{x.start_time.to_i}” }
I considered this but while 2000 > 100 isn’t it true that “100” >
“2000”. Going to an extra digit is not going to happen any time soon,
but it seemed a bit hacky to me (when I originally considered this
solution before my email to the RoR list).

-Rob


“On two occasions, I have been asked [by members of Parliament],
‘Pray, Mr. Babbage, if you put into the machine wrong figures, will
the right answers come out?’ I am not able to rightly apprehend the
kind of confusion of ideas that could provoke such a question.”
– Charles Babbage (1791-1871)

“98.5% of DNA is considered to be junk DNA with no known purpose.
Maybe it’s XML tags.” – Anon

http://www.robhulme.com/

On Thursday, July 27, 2006, at 11:07 AM, Robert H. wrote:

“2000”. Going to an extra digit is not going to happen any time soon,
– Charles Babbage (1791-1871)

“98.5% of DNA is considered to be junk DNA with no known purpose.
Maybe it’s XML tags.” – Anon

http://www.robhulme.com/
http://robhu.livejournal.com/


Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

Yeah, it is a bit hacky. However, if you print out the time value as
the unix timestamp and pad it with leading zeros, it will work.

I prefer the first method myself.

_Kevin
www.sciwerks.com