Menu
CoddyTech

وحدة Comparable

جزء من قسم البرمجة كائنية التوجه في رحلة Ruby على Coddy. الدرس 29 من 57.

تمنح الوحدة المضمّنة في Ruby Comparable الصنفَ المعاملات < و<= و== و> و>=، والطريقتين between? وclamp. وهي تحتاج إلى طريقة واحدة من الصنف: <=>، التي تُرجع عددًا سالبًا أو 0 أو عددًا موجبًا عندما يكون الكائن أصغر أو مساويًا أو أكبر:

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

الناتج:

true
true
true

الأعداد والسلاسل النصية لديها بالفعل <=>، لذا يفوّض الصنف عادةً المقارنة إلى إحدى قيمه. تعمل مقارنة المصفوفات عنصرًا بعنصر، ما يتيح الترتيب حسب عدة حقول دفعة واحدة:

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

الناتج:

true
true

تستخدم sort وmin وmax أيضًا <=>، لذا يمكن ترتيب كائنات الصنف دون كتلة. تُبقي clamp قيمةً بين قيمتين أخريين:

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

الناتج:

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

ينبغي أن تُرجع <=> القيمة nil عندما يتعذر إجراء مقارنة مع الكائن الآخر. عندئذٍ ترفع Comparable الخطأ ArgumentError عند استخدام <، وتُرجع false عند استخدام ==، بدلًا من الإخفاق بخطأ NoMethodError المربك:

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

  grams <=> other.grams
end

Weight.new(1) == 5     # false
Weight.new(1) < 5      # ArgumentError: فشلت مقارنة Weight مع 5
challenge icon

التحدي

سهل

أكمِل الصنف Weight. تقرأ Weight.parse(text) القيم 500g أو 1.2kg أو 2lb (1 lb يساوي 453.6 g) وتخزّن الغرامات. أدرِج Comparable وعرّف <=> اعتمادًا على الغرامات. تُعيد to_s الغرامات مقرّبةً إلى أقرب عدد صحيح، مثل 1200g.

يحلّل الكود المزوّد كل سطر من المدخلات، ثم يطبع الأوزان مرتّبة، والأثقل، والأخفّ، وما إذا كان الوزن الأول بين 1 kg و2 kg، والوزن الأول بعد حصره بحد أقصى قدره 1 kg.

ضع الكود في weight.rb. يحتوي main.rb على كود الإدخال/الإخراج المزوّد، ولا يمكن تعديله.

جرّب بنفسك

require_relative 'weight'

# شيفرة الإدخال/الإخراج المقدَّمة: اتركها كما هي
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 iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم Ruby عبر الإنترنت