동등성과 해시
Coddy Ruby 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 57개 중 37번째.
Ruby에는 여러 종류의 동등성이 있습니다. ==는 값의 동등성으로, 클래스에 대해 정의하는 것입니다. Hash와 uniq는 대신 두 가지 다른 메서드인 eql?과 hash를 사용합니다. ==만 정의하면 값이 같은 Point도 여전히 서로 다른 해시 키입니다:
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
nilHash는 먼저 객체에서 계산된 숫자인 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를 가져야 합니다. 서로 다른 두 객체가 우연히 해시 값을 공유할 수 있기 때문에 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?은 동일성을 유지해야 하며 절대로 재정의해서는 안 됩니다. 내장 값은 이미 이러한 규칙을 따르므로 문자열과 배열을 해시 키로 사용할 수 있습니다:
a == b # 같은 값 (직접 정의함)
a.eql?(b) # Hash 키와 uniq에 대한 같은 값 (==의 별칭)
a.hash # 숫자; 같은 객체는 같은 숫자를 반환
a.equal?(b) # 같은 객체 (절대 재정의하지 말 것)챌린지
쉬움좌표가 같은 점들이 ==, eql? 및 hash에서 동일하게 취급되고 Hash 키로 작동하도록 Point 클래스를 완성하세요. 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))}"
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 Ruby 컴파일러