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"}]
¿Fue útil?

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top