Menu
Coddy logo textTech

Eşitlik ve hash

Coddy'nin Ruby Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 37 / 57.

Ruby’de eşitliğin birkaç türü vardır. ==, sınıfınız için tanımladığınız değer eşitliğidir. Hash’ler ve uniq bunun yerine iki farklı yöntem kullanır: eql? ve hash. Yalnızca == tanımlandığında, eşit noktalar hâlâ farklı hash anahtarlarıdır:

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)

Çıktı:

true
2
nil

Bir Hash önce nesneden hesaplanan sayılar olan hash değerlerini karşılaştırır, ardından adayları eql? ile denetler. Her ikisini de == ile aynı alanlardan tanımlayın. alias eql? ==, == yöntemini yeniden kullanır ve [x, y].hash alanları birleştirir:

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

Çıktı:

2
first

Kural şudur: eql? olan nesneler aynı hash değerine sahip olmalıdır. İki farklı nesne tesadüfen aynı hash değerini paylaşabilir; bu nedenle eql? kontrol yapmaya devam eder. Ardından Hash ile sayma, kimlikler yerine değerler üzerinden çalışır:

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}" }

Çıktı:

ruby: 3
gem: 1

equal? özdeşliği korur ve asla yeniden tanımlanmamalıdır. Yerleşik değerler zaten bu kurallara uyar; dizelerin ve dizilerin karma tablolarında anahtar olarak çalışmasının nedeni budur:

a == b          # aynı değer (siz tanımlarsınız)
a.eql?(b)       # Hash anahtarları ve uniq için aynı değer (== takma adı)
a.hash          # bir sayı; eşit nesneler eşit sayılar verir
a.equal?(b)     # aynı nesne (asla yeniden tanımlamayın)
challenge icon

Görev

Kolay

Point sınıfını, aynı koordinatlara sahip noktalar ==, eql? ve hash ile eşit olacak ve Hash anahtarları olarak çalışacak şekilde tamamla. to_s, (1, 2) değerini döndürür.

Sağlanan kod, noktaları x,y satırları olarak okur. uniq ile farklı noktaların sayısını yazdırır, ardından bir Hash içinde nokta başına ziyaretleri sayar ve bunları ilk ziyaret sırasına göre (1, 2): 2 olarak yazdırır; son olarak da yeni bir Point.new(0, 0) nesnesinin anahtar olup olmadığını belirtir.

Kodun point.rb dosyasına yazılmalıdır. main.rb sağlanan girdi/çıktı kodunu içerir ve düzenlenemez.

Kendin dene

require_relative 'point'

# Sağlanan girdi/çıktı kodu: olduğu gibi bırakın
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 iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online Ruby derleyicisi