Igualdad y hash
Parte de la sección Programación orientada a objetos del Journey de Ruby de Coddy. Lección 37 de 57.
Ruby tiene varios tipos de igualdad. == es la igualdad de valores, que defines para tu clase. Los hashes y uniq usan en su lugar otros dos métodos: eql? y hash. Al definir únicamente ==, los puntos iguales siguen siendo claves de hash diferentes:
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)Salida:
true
2
nilUn Hash primero compara los valores de hash, números calculados a partir de un objeto, y después comprueba los candidatos con eql?. Define ambos a partir de los mismos campos que ==. alias eql? == reutiliza ==, y [x, y].hash combina los campos:
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])Salida:
2
firstLa regla es: los objetos que son eql? deben tener el mismo hash. Dos objetos diferentes pueden compartir un valor de hash por casualidad, por lo que eql? aún realiza la comprobación. Después, contar con un Hash funciona usando valores en lugar de identidades:
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}" }Salida:
ruby: 3
gem: 1equal? mantiene la identidad y nunca debe redefinirse. Los valores integrados ya siguen estas reglas, por eso las cadenas y los arrays funcionan como claves de hash:
a == b # mismo valor (tú lo defines)
a.eql?(b) # mismo valor para las claves de Hash y uniq (alias de ==)
a.hash # un número; los objetos iguales dan números iguales
a.equal?(b) # el mismo objeto (nunca redefinir)Desafío
FácilCompleta la clase Point para que los puntos con las mismas coordenadas sean iguales con ==, eql? y hash, y funcionen como claves de Hash. to_s devuelve (1, 2).
El código proporcionado lee los puntos como líneas x,y. Imprime el número de puntos distintos con uniq, después cuenta las visitas a cada punto en un Hash y las imprime en el orden de la primera visita como (1, 2): 2, y finalmente indica si un nuevo Point.new(0, 0) es una clave.
Tu código debe ir en point.rb. main.rb contiene el código proporcionado de entrada/salida y no se puede editar.
Pruébalo tú mismo
require_relative 'point'
# Código de entrada/salida suministrado: déjalo como está
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))}"
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Clases y objetos
Trabajar con archivosDefinir clasesVariables de instanciaMétodos y selfto_s e inspectRepaso: tarjeta de biblioteca4Encapsulación
Métodos privadosMétodos protegidosAsignadores privadosProtección del estadoRepaso: máquina expendedora7Polimorfismo y tipado pato
PolimorfismoTipado patoMétodos abstractoscase y clasesRepaso: métodos de pago2Accesores y self
Lectores y escritoresSetters personalizadosself en los métodosIdentidad e igualdadRepaso: lista de contactos5Herencia
SubclasesSobrescritura de métodosLlamar a superis_a? y ancestrosRepaso - Nómina del personal8Métodos especiales
Igualdad y hashMétodos de operadoresIndexación y adiciónColecciones personalizadasRepaso: fracciones11Proyecto: Gestión de biblioteca
Libros y miembrosPréstamo de librosPractica por tu cuenta: Compilador de Ruby online