Menu
CoddyTech

Kesetaraan dan hash

Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan Ruby di Coddy. Pelajaran 37 dari 57.

Ruby memiliki beberapa jenis kesetaraan. == adalah kesetaraan nilai, yang kamu definisikan untuk class-mu. Hash dan uniq menggunakan dua method lain: eql? dan hash. Jika hanya == yang didefinisikan, titik yang sama tetap menjadi kunci hash yang berbeda:

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)

Output:

true
2
nil

Hash pertama-tama membandingkan nilai hash, yaitu angka yang dihitung dari sebuah object, lalu memeriksa kandidat dengan eql?. Definisikan keduanya berdasarkan field yang sama seperti ==. alias eql? == menggunakan kembali ==, sedangkan [x, y].hash menggabungkan field-field tersebut:

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

Output:

2
first

Aturannya: object yang eql? harus memiliki hash yang sama. Dua object berbeda mungkin kebetulan memiliki nilai hash yang sama, karena itulah eql? tetap melakukan pemeriksaan. Jadi, penghitungan dengan Hash bekerja berdasarkan nilai, bukan identitas:

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

Output:

ruby: 3
gem: 1

equal? tetap memeriksa identitas dan tidak boleh didefinisikan ulang. Nilai bawaan sudah mengikuti aturan ini, itulah sebabnya string dan array dapat digunakan sebagai kunci Hash:

a == b          # nilai yang sama (kamu yang menentukannya)
a.eql?(b)       # nilai yang sama untuk kunci Hash dan uniq (alias dari ==)
a.hash          # sebuah angka; object yang setara menghasilkan angka yang sama
a.equal?(b)     # object yang sama (jangan pernah definisikan ulang)
challenge icon

Tantangan

Mudah

Lengkapi class Point agar titik dengan koordinat yang sama dianggap sama dengan ==, eql?, dan hash, serta dapat digunakan sebagai key Hash. to_s mengembalikan (1, 2).

Kode yang disediakan membaca titik dari baris berformat x,y. Kode mencetak jumlah titik yang berbeda dengan uniq, lalu menghitung kunjungan untuk tiap titik dalam Hash dan mencetaknya sesuai urutan kunjungan pertama sebagai (1, 2): 2, dan terakhir mencetak apakah Point.new(0, 0) yang baru merupakan key.

Tulis kodemu di point.rb. main.rb berisi kode input/output yang disediakan dan tidak boleh diedit.

Coba sendiri

require_relative 'point'

# Kode input/output yang disediakan: biarkan apa adanya
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 iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Objek

Latihan sendiri: Compiler Ruby online