Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

وحدة Comparable

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

تمنح الوحدة المضمّنة Comparable في Ruby الصنفَ العوامل < و<= و== و> و>=، والطريقتين 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 عبر الإنترنت