๐ŸŽ“ A1Learner
๐Ÿ”
0 of 34 lessons completed

Ruby Comparable

Comparable turns one comparison method into a full set of comparisons. A class defines how two of its objects order, and the shared methods do the rest.

The spaceship method

Score defines <=> by comparing its points with the points of the other score. The three prints show -1, 0, and 1.

class Score
  include Comparable
  def initialize(points)
    @points = points
  end
  def points
    @points
  end
  def <=>(other)
    @points <=> other.points
  end
end
low = Score.new(10)
high = Score.new(20)
puts low <=> high
puts low <=> Score.new(10)
puts high <=> low

Comparisons come free

Score only defines <=>. The <, >, and == lines still answer, because Comparable builds them from <=>.

class Score
  include Comparable
  def initialize(points)
    @points = points
  end
  def points
    @points
  end
  def <=>(other)
    @points <=> other.points
  end
end
low = Score.new(10)
high = Score.new(20)
puts low < high
puts high > low
puts low == Score.new(10)
puts low == high

Asking with between?

between? checks a score against a low score and a high score. Fifteen sits between ten and twenty, and five does not.

class Score
  include Comparable
  def initialize(points)
    @points = points
  end
  def points
    @points
  end
  def <=>(other)
    @points <=> other.points
  end
end
low = Score.new(10)
high = Score.new(20)
mid = Score.new(15)
small = Score.new(5)
puts mid.between?(low, high)
puts small.between?(low, high)

Sorting objects

sort reads <=> for every pair it compares. The sorted scores print from the smallest points to the largest.

class Score
  include Comparable
  def initialize(points)
    @points = points
  end
  def points
    @points
  end
  def <=>(other)
    @points <=> other.points
  end
end
scores = [Score.new(30), Score.new(10), Score.new(20)]
sorted = scores.sort
sorted.each do |score|
  puts score.points
end

Example

class Parcel
  include Comparable
  def initialize(weight)
    @weight = weight
  end
  def weight
    @weight
  end
  def <=>(other)
    @weight <=> other.weight
  end
end
light = Parcel.new(2)
heavy = Parcel.new(9)
mid = Parcel.new(5)
puts heavy > light
puts mid.between?(light, heavy)
parcels = [heavy, light, mid]
sorted = parcels.sort
sorted.each do |parcel|
  puts parcel.weight
end
puts parcels.max.weight

Key points

  • A class includes Comparable to gain its comparison methods.
  • The class must define the <=> method itself.
  • <=> answers -1, 0, or 1 for before, equal, or after.
  • The methods <, >, and == all read their answer from <=>.
  • between? takes a low value and a high value.
  • sort orders an array of the objects through <=>.

In this example, Parcel includes Comparable and defines <=> through weight. The > and between? lines answer from that one method. sort lines the parcels up by weight, and max picks the heaviest parcel.

Note

One <=> method gives the class the whole comparison set.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

What must a class define before Comparable can compare its objects?