# Finding and Sorting

**URL:** <https://www.ruby-forum.com/t/finding-and-sorting/82622>\
**Category:** Rails\
**Created:** [January 19, 2007, 4:31pm UTC](https://www.ruby-forum.com/t/finding-and-sorting/82622 "2007-01-19T16:31:46Z")\
**Posts on this page:** 3\
**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:** [January 19, 2007, 4:31pm UTC](https://www.ruby-forum.com/t/finding-and-sorting/82622/1 "2007-01-19T16:31:46Z")

</div>

I am just trying to work through David Black’s block of code from Ruby  
For Rails, on page 80.

def all  
@order = params[:order] || “number”  
sort\_proc = case @order  
when “author” then lambda {|r| [r.user.name.downcase, r.number] }  
when “status”,“title” then lambda {|r| [r.send(@order).downcase,  
r.number]}  
when “number” then lambda {|r| -r.number }  
end  
@rcrs = Rcr.find(:all).sort\_by &sort\_proc  
end

I can get this to work just fine. But how about this…if the user  
passes the “order” parameter as author, I want to sort nearly the same  
way, but with r.user.name descending. I know this errors, but I mean  
something like:  
when “author” then lambda {|r| [r.user.name.downcase DESC,  
r.number] }

How do you control the ascending/descending on one of the two sort  
parameters?

Also, in the “number” sort option, what is the - doing in the part  
-r.number? I have experimented with it, but haven’t determined what it  
is doing.

Thanks,  
Rob

---

<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:** [September 25, 2007, 10:40pm UTC](https://www.ruby-forum.com/t/finding-and-sorting/82622/2 "2007-09-25T22:40:36Z")

</div>

I hadn’t seen this code but it was a good exercise to figure out what  
was going on. Here’s how it looks to me:

(1) as for the ascending, descending, probably it would be easiest to  
simply throw a .reverse on the end of that string. This code doesn’t  
seem to be aimed at efficiency so much as clarity (I’d rather use the  
database to take care of ordering in the find), so I don’t think the  
extra method call is too heavy.

(2) the -r.number is a way of sorting descending ([1,2,3] becomes  
[-3,-2,-1])

I was happy to learn the array trick with sort\_by from this example  
though. Sort sorts arrays according to their content values, starting  
from first to last (so [[1,2],[3,4],[3,2]].sort evals to  
[[1,2],[3,2],[3,4]]. This example then uses arrays as the sort\_by map  
to sort by various criteria.

Still, I don’t understand why one would go this way instead of letting  
the database do the sorting.

Ethan

---

<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:** [September 25, 2007, 10:45pm UTC](https://www.ruby-forum.com/t/finding-and-sorting/82622/3 "2007-09-25T22:45:21Z")

</div>

removed\_email\_address@domain.invalid wrote:

> I can get this to work just fine. But how about this…if the user  
> passes the “order” parameter as author, I want to sort nearly the same  
> way, but with r.user.name descending. I know this errors, but I mean  
> something like:  
> when “author” then lambda {|r| [r.user.name.downcase DESC,  
> r.number] }
> 
> How do you control the ascending/descending on one of the two sort  
> parameters?

The easiest way to sort descending is to use the regular .sort method  
and reverse the variables coming from the block:

[“a”,“b”,“c”].sort { |x,y| y \<=\> x } #=\> [“c”,“b”,“a”]

For sorting my case insensitive name in reverse, it would look like:

Author.find(:all).sort { |x,y| y.name.downcase \<=\> x.name.downcase }

If you do this a lot you could make a method for it (I don’t think one  
already exists):

class Array  
def sort\_by\_reverse(&block)  
sort { |x,y| block.call(y) \<=\> block.call(x) }  
end  
end

Then: [“a”,“B”,“c”,“D”].sort\_by\_reverse { |s| s.downcase } #=\>  
[“D”,“c”,“B”,“a”]

I’m not sure if this is the most efficient way, or if .sort.reverse if  
more efficient, but it works.

Dan M.
