Finding and Sorting


#1

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


#2

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


#3

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.