Ruby array intersection

Two arrays containing objects do not intersect when using '&' between arrays. Please take a look at the snippet below:

ruby-1.9.2-p290 :001 > class A ruby-1.9.2-p290 :002?> include Comparable ruby-1.9.2-p290 :003?> attr_reader :key ruby-1.9.2-p290 :004?> def initialize(key) ruby-1.9.2-p290 :005?> @key = key ruby-1.9.2-p290 :006?> end ruby-1.9.2-p290 :007?> def <=> obj ruby-1.9.2-p290 :008?> @key <=> obj.key ruby-1.9.2-p290 :009?> end ruby-1.9.2-p290 :010?> end => nil ruby-1.9.2-p290 :011 > class B ruby-1.9.2-p290 :012?> attr_reader :key ruby-1.9.2-p290 :013?> def initialize(key) ruby-1.9.2-p290 :014?> @key = key ruby-1.9.2-p290 :015?> end ruby-1.9.2-p290 :016?> end => nil ruby-1.9.2-p290 :017 > A.new(1) == A.new(1) => true ruby-1.9.2-p290 :019 > B.new(1) == B.new(1) => false ruby-1.9.2-p290 :020 > a1 = [A.new(1), A.new(2), A.new(3)] => [#<A:0x000001009e2f68 @key=1>, #<A:0x000001009e2f40 @key=2>, #<A:0x000001009e2f18 @key=3>] ruby-1.9.2-p290 :021 > a2 = [A.new(3), A.new(4), A.new(5)] => [#<A:0x000001009d44e0 @key=3>, #<A:0x000001009d44b8 @key=4>, #<A:0x000001009d4490 @key=5>] ruby-1.9.2-p290 :023 > a1 | a2 => [#<A:0x000001009e2f68 @key=1>, #<A:0x000001009e2f40 @key=2>, #<A:0x000001009e2f18 @key=3>, #<A:0x000001009d44e0 @key=3>, #<A:0x000001009d44b8 @key=4>, #<A:0x000001009d4490 @key=5>] ruby-1.9.2-p290 :024 > a1 & a2 => [] 

should not return a1 and a2:

 [#<A:0x000001009e2f18 @key=3>] 

or, I just missed something ...

+6
source share
1 answer

No, you need to implement hash equality for Array#& and Array#| for work (its implementation only under normal comparisons will be O(n * m) ). Note that Array#| also returned the wrong result: it includes duplicates.

Such an equality method can be implemented as follows:

  def hash @key.hash ^ A.hash # just to get a different hash than the key end alias eql? == 

Also, your <=> does not work if the other object does not respond to #key. == must not fail; it must return false if two objects cannot compare. Is this also one of those methods in which you do not want to use respond_to? , but rather is_a? : You do not want the movie to be equal to the book, because they have the same title.

 def <=>(other) @key <=> other.key if other.is_a? A end 
+9
source

Source: https://habr.com/ru/post/899154/


All Articles