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

المساواة والتجزئة

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

لدى Ruby عدة أنواع من المساواة. == هي مساواة القيم، التي تعرّفها لفئتك. تستخدم Hashes وuniq طريقتين أخريين بدلًا من ذلك: eql? وhash. عند تعريف == فقط، تظل النقاط المتساوية مفاتيح مختلفة في التجزئة:

class Point
  attr_reader :x, :y

  def initialize(x, y)
    @x = x
    @y = y
  end

  def ==(other)
    other.is_a?(Point) && x == other.x && y == other.y
  end
end

a = Point.new(1, 2)
b = Point.new(1, 2)
puts a == b
puts [a, b].uniq.size
puts({ a => "first" }[b].inspect)

الناتج:

true
2
nil

يقارن Hash أولًا قيم hash، وهي أرقام محسوبة من كائن، ثم يتحقق من المرشحين باستخدام eql?. عرّف كليهما باستخدام الحقول نفسها المستخدَمة في ==. يعيد alias eql? == استخدام ==، بينما تجمع [x, y].hash الحقول:

class Point
  attr_reader :x, :y

  def initialize(x, y)
    @x = x
    @y = y
  end

  def ==(other)
    other.is_a?(Point) && x == other.x && y == other.y
  end
  alias eql? ==

  def hash
    [x, y].hash
  end
end

a = Point.new(1, 2)
b = Point.new(1, 2)
puts [a, b, Point.new(3, 4)].uniq.size
puts({ a => "first" }[b])

الناتج:

2
first

القاعدة هي: يجب أن يكون للكائنات التي eql? القيمة نفسها في hash. قد تشترك كائنات مختلفة في قيمة hash بالصدفة، ولهذا السبب يستمر eql? في التحقّق. بعد ذلك، يعمل العد باستخدام Hash على القيم بدلًا من الهويات:

class Word
  attr_reader :text

  def initialize(text)
    @text = text.downcase
  end

  def ==(other)
    other.is_a?(Word) && text == other.text
  end
  alias eql? ==

  def hash
    text.hash
  end
end

counts = Hash.new(0)
%w[Ruby ruby RUBY gem].each { |t| counts[Word.new(t)] += 1 }
counts.each { |word, n| puts "#{word.text}: #{n}" }

الناتج:

ruby: 3
gem: 1

يظل equal? خاصًا بالهوية، ولا ينبغي أبدًا إعادة تعريفه. تتبع القيم المضمّنة هذه القواعد بالفعل، ولهذا السبب تعمل السلاسل والمصفوفات كمفاتيح للتجزئة:

a == b          # نفس القيمة (أنت تعرّفها)
a.eql?(b)       # نفس القيمة لمفاتيح Hash و uniq (اسم مستعار لـ ==)
a.hash          # رقم؛ الكائنات المتساوية تعطي أرقامًا متساوية
a.equal?(b)     # نفس الكائن (لا تعِد تعريفه أبدًا)
challenge icon

التحدي

سهل

أكمل الصنف Point بحيث تكون النقاط ذات الإحداثيات نفسها متساوية باستخدام == وeql? وhash، وتعمل كمفاتيح في Hash. تُرجع to_s القيمة (1, 2).

يقرأ الكود المزوَّد النقاط على شكل أسطر x,y. ويطبع عدد النقاط المميّزة باستخدام uniq، ثم يحسب عدد الزيارات لكل نقطة في Hash ويطبعها بترتيب الزيارة الأولى على الشكل (1, 2): 2، وأخيرًا يطبع ما إذا كان Point.new(0, 0) الجديد مفتاحًا.

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

جرّب بنفسك

require_relative 'point'

# كود الإدخال/الإخراج المُزوَّد: أبقِه كما هو
input = []
while (line = gets)
  input << line.chomp
end
points = input.map { |line| Point.new(*line.split(",").map(&:to_i)) }
puts "distinct: #{points.uniq.size}"
visits = Hash.new(0)
points.each { |pt| visits[pt] += 1 }
visits.each { |pt, n| puts "#{pt}: #{n}" }
puts "origin visited: #{visits.key?(Point.new(0, 0))}"
quiz iconاختبر نفسك

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

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

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