Menu
Coddy logo textTech

Das Comparable-Modul

Teil des Abschnitts Objektorientierte Programmierung der Ruby-Journey von Coddy. Lektion 29 von 57.

Das in Ruby integrierte Modul Comparable gibt einer Klasse die Operatoren <, <=, ==, >, >= sowie die Methoden between? und clamp. Es benötigt eine Methode der Klasse: <=>, die eine negative Zahl, 0 oder eine positive Zahl zurückgibt, wenn das Objekt kleiner, gleich oder größer ist:

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))

Ausgabe:

true
true
true

Zahlen und Zeichenketten verfügen bereits über <=>, daher delegiert eine Klasse üblicherweise an einen ihrer Werte. Der Vergleich von Arrays funktioniert Element für Element, wodurch nach mehreren Feldern gleichzeitig sortiert wird:

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

Ausgabe:

true
true

sort, min und max verwenden ebenfalls <=>, sodass Objekte der Klasse ohne Block sortiert werden können. clamp hält einen Wert zwischen zwei anderen:

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))

Ausgabe:

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

<=> sollte nil zurückgeben, wenn das andere Objekt nicht verglichen werden kann. Comparable löst dann für < ArgumentError aus und gibt für == false zurück, anstatt mit einem verwirrenden NoMethodError fehlzuschlagen:

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

  grams <=> other.grams
end

Weight.new(1) == 5     # false
Weight.new(1) < 5      # ArgumentError: comparison of Weight with 5 failed
challenge icon

Aufgabe

Einfach

Vervollständige die Klasse Weight. Weight.parse(text) liest 500g, 1.2kg oder 2lb (1 lb entspricht 453.6 g) und speichert die Gramm. Binde Comparable ein und definiere <=> anhand der Gramm. to_s gibt die auf eine ganze Zahl gerundeten Gramm zurück, zum Beispiel 1200g.

Der bereitgestellte Code verarbeitet jede Eingabezeile und gibt anschließend die sortierten Gewichte, das schwerste, das leichteste, aus, ob das erste Gewicht zwischen 1 kg und 2 kg liegt, sowie das auf höchstens 1 kg begrenzte erste Gewicht.

Dein Code gehört in weight.rb. main.rb enthält den bereitgestellten Eingabe-/Ausgabecode und darf nicht bearbeitet werden.

Probier es selbst

require_relative 'weight'

# Gelieferter Ein-/Ausgabe-Code: belasse ihn wie er ist
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 iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Ruby-Compiler