2

当第一个对象相等时,如何通过辅助键对多个对象进行排序?

在我的Book课堂上,我有以下用于排序的方法

def <=>(other)
  printed_on <=> other.printed_on
end

现在我需要对同一天 ( printed_on = other.printed_on) 印刷的书籍进行排序page_number

因为sort_by你可以传递一个键数组,我试过了

 def <=>(other)
   [printed_on <=> other.printed_on, page_number <=> other.page_number]
 end

但我明白了

[1, 1]:Array 的未定义方法 `>'

4

3 回答 3

4

Arrays 按字典顺序进行比较粗体强调我的):

数组以“元素方式”的方式进行比较;的第一个元素aryother_ary使用<=>运算符的第一个元素进行比较,然后是第二个元素中的每一个,等等……只要任何此类比较的结果不为零(即两个对应的元素不相等),结果就是返回整个数组比较。

[这只是一种令人费解的说法,即“按Array字典顺序比较 s”。]

因此,您可以简单地使用 anArray进行比较:

def <=>(other)
  [printed_on, page_number] <=> [other.printed_on, other.page_number]
end

您的方法违反了(粗体强调我的)的合同:<=>

您的实现#<=>应返回以下值之一:-10或。1nil

符合条件的实现只有四个允许的返回值<=>

  • -1: 少于
  • 0: 平等的
  • +1: 比...更棒
  • nil:无法比较(部分排序)

您没有返回这四个,而是返回一个Array. 与往常一样,如果您违反合同,可能会发生奇怪的事情。

于 2019-10-28T07:23:28.063 回答
3

您正在寻找:

[printed_on, page_number] <=> [other.printed_on, other.page_number]

<=>必须返回一个数字(通常它应该是 1、0 或 1,但 ruby​​ 允许任何数值)或 nil 如果无法进行比较)。您的实现返回一个由两个数字组成的数组,这会导致问题,因为它试图将所述数组与 0 进行比较。

于 2019-10-28T07:21:22.870 回答
1

您还可以通过nonzero?和链接比较||

def <=>(other)
  (printed_on <=> other.printed_on).nonzero? || page_number <=> other.page_number
end

printed_on <=> other.printed_on如果其结果非零,则表达式返回,page_number <=> other.page_number否则返回。

您可能希望为非Book对象添加保护子句:

def <=>(other)
  return nil unless other.is_a?(Book)

  (printed_on <=> other.printed_on).nonzero? || page_number <=> other.page_number
end
于 2019-10-28T09:09:41.687 回答