Menu
Coddy logo textTech

Il modulo Comparable

Fa parte della sezione Programmazione orientata agli oggetti del percorso Ruby di Coddy. Lezione 29 di 57.

Il modulo integrato Comparable di Ruby fornisce a una classe gli operatori <, <=, ==, >, >= e i metodi between? e clamp. Richiede un metodo della classe: <=>, che restituisce un numero negativo, 0 o un numero positivo quando l’oggetto è rispettivamente minore, uguale o maggiore:

class Weight
  include Comparable
  attr_reader :grams

  def initialize(grams)
    @grams = grams
  end

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

a = Weight.new(500)
b = Weight.new(1200)
puts a < b
puts a == Weight.new(500)
puts b.between?(a, Weight.new(2000))

Output:

true
true
true

Numeri e stringhe hanno già <=>, quindi di solito una classe delega a uno dei suoi valori. Il confronto tra array funziona elemento per elemento, consentendo di ordinare in base a più campi contemporaneamente:

class Person
  include Comparable
  attr_reader :last, :first

  def initialize(first, last)
    @first = first
    @last = last
  end

  def <=>(other)
    [last, first] <=> [other.last, other.first]
  end
end

a = Person.new("Ada", "Lovelace")
b = Person.new("Alan", "Turing")
c = Person.new("Byron", "Lovelace")
puts a < c
puts b > c

Output:

true
true

sort, min e max usano anche <=>, quindi gli oggetti della classe possono essere ordinati senza un blocco. clamp mantiene un valore tra altri due:

class Weight
  include Comparable
  attr_reader :grams

  def initialize(grams)
    @grams = grams
  end

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

  def to_s
    "#{grams}g"
  end
end

list = [Weight.new(900), Weight.new(150), Weight.new(400)]
puts list.sort.join(", ")
puts list.max
puts Weight.new(5000).clamp(Weight.new(0), Weight.new(1000))

Output:

150g, 400g, 900g
900g
1000g

<=> dovrebbe restituire nil quando l'altro oggetto non può essere confrontato. Comparable quindi genera ArgumentError per < e restituisce false per ==, invece di fallire con un NoMethodError fuorviante:

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

  grams <=> other.grams
end

Weight.new(1) == 5     # false
Weight.new(1) < 5      # ArgumentError: confronto di Weight con 5 non riuscito
challenge icon

Sfida

Facile

Completa la classe Weight. Weight.parse(text) legge 500g, 1.2kg o 2lb (1 lb corrisponde a 453.6 g) e memorizza i grammi. Includi Comparable e definisci <=> sui grammi. to_s restituisce i grammi arrotondati al numero intero più vicino, come 1200g.

Il codice fornito analizza ogni riga di input, poi stampa i pesi in ordine, il più pesante, il più leggero, indica se il primo peso è compreso tra 1 kg e 2 kg e stampa il primo peso limitato a un massimo di 1 kg.

Il tuo codice va inserito in weight.rb. main.rb contiene il codice di input/output fornito e non può essere modificato.

Provalo tu

require_relative 'weight'

# Codice di input/output fornito: lascialo così com'è
input = []
while (line = gets)
  input << line.chomp
end
weights = input.map { |line| Weight.parse(line) }
puts "sorted: #{weights.sort.join(", ")}"
puts "heaviest: #{weights.max}"
puts "lightest: #{weights.min}"
puts "first between 1kg and 2kg: #{weights[0].between?(Weight.parse("1kg"), Weight.parse("2kg"))}"
puts "first clamped: #{weights[0].clamp(Weight.parse("0g"), Weight.parse("1kg"))}"
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Ruby online