Extendiendo método uniq
-
21-09-2019 - |
Pregunta
Este es Rubí 1.8 Pregunta:
Todos sabemos cómo utilizar Array#uniq
:
[1,2,3,1].uniq #=> [1,2,3]
Sin embargo me pregunto si podemos parchear mono en una manera de trabajar con objetos complejos. El comportamiento actual es la siguiente:
[{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq
#=> [{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}]
El solicitada es:
[{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq
#=> [{"three"=>"3"}, {"three"=>"4"}]
Solución
Ya se trabaja para mí en 1.8.7.
1:~$ ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
1:~$ irb -v
irb 0.9.5(05/04/13)
1:~$ irb
>> [{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq
=> [{"three"=>"3"}, {"three"=>"4"}]
Otros consejos
Para hacer el arreglo # uniq trabajo para cualquier Objeto debe invalidar dos métodos:? Hash y eql
Todos los objetos tienen un método de hash que calcula el valor de hash para ese objeto, por lo que para dos objetos sean iguales a sus valores cuando hash también debe ser igual.
Ejemplo - un usuario es único cuando su dirección de correo electrónico es único:
class User
attr_accessor :name,:email
def hash
@email.hash
end
def eql?(o)
@email == o.email
end
end
>> [User.new('Erin Smith','roo@example.com'),User.new('E. Smith','roo@example.com')].uniq
=> [#<User:0x1015a97e8 @name="Erin Smith", @email="maynurd@example.com"]
El problema es que Hash#hash
y Hash#eql?
tanto dar resultados falsos en Ruby 1.8.6. Este es uno de los parches mono muy raros que he estado dispuesto a realizar, debido a este error rompe gravemente a una gran cantidad de código - en funciones memoizing particulares. Sólo tenga cuidado con los parches de mono que no anular el comportamiento no roto.
Así que:
class Hash
if {}.hash != {}.hash
def hash
# code goes here
end
end
if !{}.eql?({})
def eql?(other)
# code goes here
end
end
end
Pero si estás haciendo algo en el que controlar el entorno de despliegue, solo producirá un error si la aplicación se inicia con 1.8.6.
¿Qué tal esto?
h={}
[{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].select {|e| need=!h.key?(e) ; h[e]=1 ; need}
#=> [{"three"=>"3"}, {"three"=>"4"}]
Me he encontrado esto mismo muchas veces. la igualdad de hash en Ruby 1.8.6 está roto:
require 'test/unit'
class TestHashEquality < Test::Unit::TestCase
def test_that_an_empty_Hash_is_equal_to_another_empty_Hash
assert({}.eql?({}), 'Empty Hashes should be eql.')
end
end
pases en Ruby 1.9 y Ruby 1.8.7, falla en Ruby 1.8.6.
1.8.7 :039 > [{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq {|x|x.values}
=> [{"three"=>"3"}, {"three"=>"4"}]
1.8.7 :040 > [{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq {|x|x.keys}
=> [{"three"=>"3"}]
¿Qué tal algo así? simplemente uniq_by el valor hash o clave hash a través del bloque.