2009-10-30 21 views
5

Estoy escribiendo una aplicación de Ruby en este momento que va a buscar en twitter varias cosas. Uno de los problemas que voy a enfrentar es el de los resultados compartidos entre búsquedas muy próximas entre sí. Los resultados se devuelven en una matriz de objetos, cada uno de los cuales es un solo tweet. Conozco el método Array.uniq en ruby, que devuelve una matriz con todos los duplicados eliminados.¿Quitar objetos idénticos en Ruby?

Mi pregunta es esta. ¿Elimina el método uniq los duplicados en la medida en que estos objetos apuntan al mismo espacio en la memoria o que contienen información idéntica?

Si es el primero, ¿cuál es la mejor manera de eliminar duplicados de una matriz en función de su contenido?

Respuesta

10

que hace el método uniq eliminar duplicados en la medida en que estos objetos apuntan a el mismo espacio de memoria o que contienen información idéntica ?

El método se basa en el método eql? por lo que elimina todos los elementos donde a.eql? (B) devuelve verdadero. El comportamiento exacto depende del objeto específico que está tratando.

Las cadenas, por ejemplo, se consideran iguales si contienen el mismo texto independientemente de que compartan la misma asignación de memoria.

a = b = "foo" 
c = "foo" 

[a, b, c].uniq 
# => ["foo"] 

Esto es cierto para la mayoría de los objetos principales, pero no para los objetos ruby.

class Foo 
end 

a = Foo.new 
b = Foo.new 

a.eql? b 
# => false 

Rubí le anima a redefinir el operador == dependiendo de su contexto de clase.

En su caso específico, sugiero crear un objeto que represente un resultado de Twitter e implementar su lógica de comparación para que Array.uniq se comporte como espera.

class Result 

    attr_accessor :text, :notes 

    def initialize(text = nil, notes = nil) 
    self.text = text 
    self.notes = notes 
    end 

    def ==(other) 
    other.class == self.class && 
    other.text == self.text 
    end 
    alias :eql? :== 

end 

a = Result.new("first") 
b = Result.new("first") 
c = Result.new("third") 

[a, b, c].uniq 
# => [a, c] 
+0

gracias, implementé el método requerido en la clase y parece estar funcionando ahora. afortunadamente, lo único que realmente necesito comparar es la identificación única para cada tweet :) Supongo que 'other.class = self.class' debe ser' other.class == self.class'? –

+0

Sí, tienes razón. Fijo. –

+1

No pude hacer que esto funcione sin sobreescribir el método 'hash' también. Ver http://www.rabbitcreative.com/2008/01/23/comparing-custom-objects-in-ruby-using-uniq/ – spier

0

creo que Array.uniq detecta duplicados a través de los objetos eql? o == métodos, lo que significa su comparación basada en el contenido, no la ubicación en la memoria (asumiendo que los objetos proporcionan una implementación significativa de eql? basado en el contenido).

6

Para cualquier otra persona tropezar con esta pregunta, parece que las cosas han cambiado un poco desde que se pidió por primera vez esta pregunta y en las nuevas versiones de Ruby (1.9.3 por lo menos), Array.uniq asume que el objeto también tiene una la implementación significativa del método #hash, además de .eql? o ==.

Cuestiones relacionadas