Estoy tratando de usar el operador bit a bit (&) para las matrices en Ruby on Rails
Cuando tengo las matrices de tipo simple
one = ["one", "two", "three"] two = ["one", "two", "three"]Y tener este código
puts (one & two)Obtengo la salida:
uno dos tres
Sin embargo, cuando tengo matrices de tipos complejos
list1 = [Someitem.new("1", "item1"),Someitem.new("2", "item2"),Someitem.new("3", "item3"),Someitem.new("4", "item4")] list2 = [Someitem.new("1", "item1"),Someitem.new("2", "item2"),Someitem.new("3", "item3"),Someitem.new("4", "item4")]Para la clase en la que anulo el método to_s
class Someitem attr_accessor :item_id, :item_name def initialize(item_id, item_name) self.item_id = item_id; self.item_name= item_name; end def to_s item_name end endY tener este código
puts (list1 & list2)no obtengo nada en la salida
¿Qué puedo hacer para obtener el resultado de las matrices de tipos complejos usando el operador bit a bit & para encontrar valores comunes dentro de esas dos listas?
Los documentos de Ruby 3.0 para Array#& dicen:
se comparan los artículos usando
eql?
Los documentos de Ruby 2.7 para Array#& dicen:
¿Compara elementos usando su
hashyeql?metodos para la eficiencia
Entonces, para que esto funcione para su clase, ¿debe implementar / anular eql? y (para compatibilidad con 2.7) hash de acuerdo con los documentos. Hay muchas maneras de hacer esto, aquí hay un enfoque simple:
class Someitem # ... def hash [item_id, item_name].hash end def eql?(other) return false unless other.is_a?(Someitem) [item_id, item_name] == [other.item_id, other.item_name] end alias == eql? # <- this isn't needed but convenient end La implementación anterior usa item_id y item_name para calcular el hash del objeto y determinar la igualdad del objeto:
Someitem.new("1", "item1").hash == Someitem.new("1", "item1").hash #=> true Someitem.new("1", "item1").eql? Someitem.new("1", "item1") #=> true [Someitem.new("1", "item1")] & [Someitem.new("1", "item1")] #=> [#<Someitem:0x00007f8ff505d228 @item_id="1", @item_name="item1">]En primer lugar, mientras que Integer#& es el operador AND bit a bit, Array#& es el operador de intersección de conjuntos (aunque encuentro el término "conjunto" rejilla porque una matriz no es un conjunto).
Pareces estar asumiendo que
Someitem.new("1", "item1") == Someitem.new("1", "item1") #=> trueSin embargo, las dos instancias no son el mismo objeto, así que de hecho:
Someitem.new("1", "item1") == Someitem.new("1", "item1") #=> false Recordando que cada objeto tiene un object_id único, considere lo siguiente:
list1.map(&:object_id) #=> [1520, 1540, 1560, 1580] list2.map(&:object_id) #=> [1600, 1620, 1640, 1660] Como [1520, 1540, 1560, 1580] y [1600, 1620, 1640, 1660] no tienen elementos comunes, vemos que su intersección está vacía:
list1.map(&:object_id) & list2.map(&:object_id) #=> [1520, 1540, 1560, 1580] & [1600, 1620, 1640, 1660] #=> []Cuando hay matrices involucradas, & es en realidad la intersección , no es bitwise AND a bit.
Para devolver los elementos comunes entre sus listas, se llama al método #hash .
Para su primer ejemplo, llamar a "one".hash devuelve el mismo valor todo el tiempo, lo que en realidad es un éxito.
"one".hash # => 103347303317675750 "one".hash # => 103347303317675750En el segundo ejemplo, trabaja con diferentes instancias que, por supuesto, no coinciden.
Someitem.new("1", "item1").hash # => a_value Someitem.new("1", "item1").hash # => another_valueSi pasa la misma instancia a ambas matrices, coincidirá.
a = Someitem.new("1", "item1") a.hash # => a_value a.hash # => same_value_as_above list1 = [a] list2 = [a] list1 & list2 # => [a]