【问题标题】:Overriding Ruby's spaceship operator <=>覆盖 Ruby 的宇宙飞船运算符 <=>
【发布时间】:2011-03-04 18:44:53
【问题描述】:

我正在尝试重写 Ruby 的 (宇宙飞船)运算符来对苹果和橙子进行排序,以便苹果首先按重量排序,橙子其次,按甜度排序。像这样:

module Fruity
  attr_accessor :weight, :sweetness

  def <=>(other)
    # use Array#<=> to compare the attributes
    [self.weight, self.sweetness] <=> [other.weight, other.sweetness]
  end
  include Comparable
end

class Apple
include Fruity

def initialize(w)
  self.weight = w
end

end

class Orange
include Fruity

def initialize(s)
  self.sweetness = s
end

end

fruits = [Apple.new(2),Orange.new(4),Apple.new(6),Orange.new(9),Apple.new(1),Orange.new(22)]

p fruits

#should work?
p fruits.sort

但这不起作用,有人可以告诉我在这里做错了什么,或者更好的方法吗?

【问题讨论】:

标签: ruby-on-rails ruby oop sorting spaceship-operator


【解决方案1】:

您的问题是您只初始化任一侧的一个属性,另一个仍将是nilnil 没有在 Array#&lt;=&gt; 方法中处理,这最终会杀死排序。

有几种方法可以首先处理这个问题,就像这样

[self.weight.to_i, self.sweetness.to_i] <=> [other.weight.to_i, other.sweetness.to_i]

nil.to_i 为您提供0,这将使这项工作正常进行。

【讨论】:

  • 谢谢,它成功了。它们按重量排序,然后按甜度排序,但按降序排列。有没有一种“最好”的方式来让它们升序?
  • 让我澄清一下我的上述评论——如果我进行以下更改:[se​​lf.weight.to_i, self.sweetness.to_i] [other.weight.to_i, other.sweetness. to_i] 我让橙子先上升,然后苹果上升,但我无法让苹果先上升,然后橙子上升。我尝试过排列数组,甚至在没有运气的情况下玩弄 Array#reverse。另外,Comparable mixin 是否包含在 定义之前或之后是否重要?无论哪种方式,我都得到了相似的结果。
  • 把包含放在哪里并不重要。也许试试 result.sort.reverse ?不是最好的方法,但可能是最直接的
  • 先给我橙子,然后是苹果,但我试图让苹果先升序排序,然后橙子升序。仍然没有运气。有人有什么想法吗?
  • 好的,那么为什么 Array#sort 不使用自己的 方法来执行比较,而是使用我重写的方法?这不违反 ruby​​ 的动态方法查找吗?
【解决方案2】:

可能已经晚了,不过……

添加以下猴子补丁

class Array
  def to_i(default=Float::INFINITY)
    self.map do |element|
      element.nil? ? default : element.to_i
    end
  end
end

并更改Fruity::&lt;=&gt; to的正文

[self.weight, self.sweetness].to_i <=> [other.weight, other.sweetness].to_i

【讨论】:

  • 抱歉,这是个坏建议。 (猴子修补总是如此,但这个问题可以更优雅地解决)。像这样的猴子补丁可以炸毁很多其他的东西。
猜你喜欢
  • 2010-10-24
  • 2021-08-07
  • 1970-01-01
  • 2021-07-27
  • 1970-01-01
  • 2011-01-30
  • 1970-01-01
相关资源
最近更新 更多