שוויון ו-hash
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Ruby של Coddy. שיעור 37 מתוך 57.
ל־Ruby יש כמה סוגים של שוויון. == הוא שוויון לפי ערך, שאותו מגדירים עבור המחלקה שלך. Hashes ו־uniq משתמשים בשתי מתודות אחרות במקום זאת: eql? ו־hash. כשמגדירים רק את ==, נקודות שוות עדיין נחשבות למפתחות שונים ב־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? מחזירים true חייב להיות אותו 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: 1equal? מציין זהות ויש להשאירו ללא הגדרה מחדש. ערכים מובנים כבר פועלים לפי הכללים האלה, ולכן מחרוזות ומערכים יכולים לשמש כמפתחות של Hash:
a == b # אותו ערך (אתם מגדירים אותו)
a.eql?(b) # אותו ערך עבור מפתחות Hash ו-uniq (כינוי של ==)
a.hash # מספר; אובייקטים שווים מחזירים מספרים שווים
a.equal?(b) # אותו אובייקט (לעולם אין להגדיר מחדש)אתגר
קלהשלימו את המחלקה 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))}"
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
3מתודות ומשתנים של מחלקה
מתודות של מחלקהמשתני מופע של מחלקהקבועיםמתודות ליצירת מופעיםסיכום – קודי קופוןתרגלו בעצמכם: קומפיילר Ruby אונליין