8

我有一个 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,然后sort!。最红宝石的方法是什么?

4

2 回答 2

12

您应该始终按相同的标准进行排序以确保有意义的顺序。如果比较两个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 < b < c < 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_bysort_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(在这种情况下,您希望由数据库服务器完成排序)。
于 2010-04-14T00:54:40.997 回答
4

或者,您可以一举在数组中进行排序,唯一的问题是处理其中一个属性为 nil 的情况,尽管如果您通过选择适当的 nil 保护知道数据集,仍然可以处理这种情况。此外,从您的伪代码中也不清楚日期和位置比较是否按优先顺序或一个或另一个列出(即,如果两者都存在,则使用日期)。第一个解决方案假设使用,类别,然后是日期,然后是位置

def <=>(other)
    [self.category, self.date, self.position] <=> [other.category, other.date, other.position]
end

第二个假设它的日期或位置

def <=>(other)
    if self.date && other.date
        [self.category, self.date] <=> [other.category, other.date]
    else
        [self.category, self.position] <=> [other.category, other.position]
    end
end
于 2010-04-14T06:27:02.643 回答