我有一个Post对象的集合,我希望能够根据这些条件对它们进行排序:
>首先,按类别(新闻,事件,实验室,投资组合等)
>然后按日期,如果是日期,或按位置,是否为其设置了特定索引
一些帖子将有日期(新闻和事件),其他帖子将有明确的职位(实验室和投资组合).
我希望能够调用posts.sort !,所以我已经覆盖了< =>,但我正在寻找按这些条件排序的最有效方法.以下是伪方法:
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
看起来我必须实际排序两次,而不是将所有内容都塞进那个方法中.像sort_by_category,然后排序!最ruby的方法是什么?
解决方法
您应该始终按相同的标准排序,以确保有意义的订单.如果比较两个零日期,那么该位置将判断订单是正常的,但是如果将一个零日期与设定日期进行比较,您必须决定哪个日期先行,而不管位置如何(例如通过将零映射到一天)过去的方式).
否则想象如下:
a.date = nil ; a.position = 1 b.date = Time.now - 1.day ; b.position = 2 c.date = Time.now ; c.position = 0
根据您的原始标准,您将拥有:a< b< c<一个.那么,哪一个是最小的? 您还想立即进行排序.对于你的< =>实现,使用#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'
与旧款ruby一起使用.>我假设Post不是ActiveRecord :: Base的子类(在这种情况下,您希望排序由db服务器完成).