Redefining Ruby Spaceship Operator <=>

I am trying to redefine the Ruby <=> operator (spaceship) for sorting apples and oranges, so that apples are sorted by weight first, and oranges are the second sorted by sweetness. For instance:

 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 

But this does not work, can someone say what I am doing wrong here, or is there a better way to do this?

+4
source share
2 answers

Your problem is that you only initialize one of the properties on both sides, the other is nil anyway. nil not processed by the Array#<=> method, which kills the sort.

There are several ways to solve the problem, first of all, something like this

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

nil.to_i gives you 0 , which will make this work.

+11
source

Maybe late, though ...

add the following monkeypatch file

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

And change the body of Fruity::<=> to

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

Source: https://habr.com/ru/post/1313045/


All Articles