Menu
CoddyTech

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