Вы всегда должны сортировать по одним и тем же критериям, чтобы обеспечить значимый порядок. Если сравнивать две даты nil
, то хорошо, что position
будет судить о порядке, но если сравнивать одну дату nil
с установленной датой, вы должны решить, какая из них идет первой, независимо от позиции (например, сопоставляя nil
с прошлым днем).
В противном случае представьте следующее:
a.date = nil ; a.position = 1
b.date = Time.now - 1.day ; b.position = 2
c.date = Time.now ; c.position = 0
По вашим первоначальным критериям у вас будет: a
Вы также хотите сделать сортировку сразу. Для реализации <=>
используйте #nonzero?
:
def <=>(other)
return nil unless other.is_a?(Post)
(self.category <=> other.category).nonzero? ||
((self.date || AGES_AGO) <=> (other.date || AGES_AGO)).nonzero? ||
(self.position <=> other.position).nonzero? ||
0
end
Если вы используете свои критерии сравнения только один раз или если этот критерий не универсален и, следовательно, не хотите определять <=>
, вы можете использовать sort
с блоком:
post_ary.sort{|a, b| (a.category <=> ...).non_zero? || ... }
Еще лучше, есть sort_by
и sort_by!
, которые вы можете использовать для построения массива, с чем сравнивать, с каким приоритетом:
post_ary.sort_by{|a| [a.category, a.date || AGES_AGO, a.position] }
Кроме того, использование sort_by
дает преимущество в том, что вы можете получить только хорошо упорядоченные критерии.
Примечания:
sort_by!
был введен в Ruby 1.9.2. Вы можете require 'backports/1.9.2/array/sort_by'
использовать его со старыми рубинами.
- Я предполагаю, что
Post
не является подклассом ActiveRecord::Base
(в этом случае вы хотите, чтобы сортировка выполнялась сервером БД).