I have a collection of Post objects and I want to be able to sort them based on these conditions:
- First, by category (news, events, labs, portfolio, etc.)
- Then by date, if date, or by position, if a specific index was set for it
Some posts will have dates (news and events), others will have explicit positions (labs, and portfolio).
I want to be able to call posts.sort!, so I’ve overridden <=>, but am looking for the most effective way of sorting by these conditions. Below is a pseudo method:
def <=>(other)
# first, everything is sorted into
# smaller chunks by category
self.category <=> other.category
# then, per category, by date or position
if self.date and other.date
self.date <=> other.date
else
self.position <=> other.position
end
end
It seems like I’d have to actually sort two separate times, rather than cramming everything into that one method. Something like sort_by_category, then sort!. What is the most ruby way to do this?
You should always sort by the same criteria to insure a meaningful order. If comparing two
nildates, it is fine that thepositionwill judge of the order, but if comparing onenildate with a set date, you have to decide which goes first, irrespective of the position (for example by mappingnilto a day way in the past).Otherwise imagine the following:
By your original criteria, you would have: a < b < c < a. So, which one is the smallest??
You also want to do the sort at once. For your
<=>implementation, use#nonzero?:If you use your comparison criteria just once, or if that criteria is not universal and thus don’t want to define
<=>, you could usesortwith a block:Better still, there is
sort_byandsort_by!which you can use to build an array for what to compare in which priority:Besides being shorter, using
sort_byhas the advantage that you can only obtain a well ordered criteria.Notes:
sort_by!was introduced in Ruby 1.9.2. You canrequire 'backports/1.9.2/array/sort_by'to use it with older Rubies.Postis not a subclass ofActiveRecord::Base(in which case you’d want the sort to be done by the db server).