2012-04-14 12 views
5

De acuerdo con Set doc, los elementos de un conjunto se comparan usando eql?.Conjunto con regla personalizada

tengo una clase como:

class Foo 
    attr_accessor :bar, :baz 

    def initialize(bar = 1, baz = 2) 
    @bar = bar 
    @baz = baz 
    end 

    def eql?(foo) 
    bar == foo.bar && baz == foo.baz 
    end 
end 

En la consola:

f1 = Foo.new 
f2 = Foo.new 
f1.eql? f2 #=> true 

Pero ...

s = Set.new 
s << f1 
s << f2 
s.size #=> 2 

Debido a que es igual a f1f2, s debe no incluir tanto de ellos.

¿Cómo hacer que los set rechacen elementos con una regla personalizada?

Respuesta

7

Los documentos que enlace a decir de manera explícita (el énfasis es mío):

La igualdad de cada par de elementos se determinan de acuerdo con Object#eql?
y Object#hash, ya que utiliza SetHash como almacenamiento.

Si se agrega un método hash a su clase que devuelve el mismo valor para eql? objetos, funciona:

# With your current class 

f1, f2 = Foo.new, Foo.new 
p f1.eql?(f2) 
#=> true 
p f1.hash==f2.hash 
#=> false 
p Set[f1,f2].length 
#=> 2 

# Fix the problem 
class Foo 
    def hash 
    [bar,hash].hash 
    end 
end 

f1, f2 = Foo.new, Foo.new 
p f1.eql?(f2) 
#=> true 
p f1.hash==f2.hash 
#=> true 
p Set[f1,f2].length 
#=> 1 

Para ser honesto, nunca he tenido un gran sentido de la forma de escribir a buen método personalizado hash cuando se trata de valores múltiples.

+0

¿Qué debo hacer? – apneadiving

+0

@apneadiving Ver mi edición. – Phrogz

+3

¿No puedes simplemente usar '[bar, baz] .hash' como un hash? –

0

De acuerdo con el libro The Ruby Programming Language (co-escrito por Yukihiro Matsumoto, creador del lenguaje Ruby), la receta de uso general para el método hash implica el uso de algunas constantes numéricas (17/37). Por ejemplo dado solución sugerida sería:

def hash 
    code = 17 
    code = 37*code + @bar.hash 
    code = 37*code + @baz.hash 
    code 
end 

Así que, en general, nos estamos repitiendo "Código = 37 * Código + @ x.hash" línea para cada variable de instancia significativa (@x).

+0

por cierto: se menciona que este enfoque está adaptado del libro Effective Java de Joshua Bloch (Prentice Hall) – Kotu

Cuestiones relacionadas