Ruby数组交集

6

当两个包含对象的数组之间使用“&”运算符时,不会返回交集结果。请查看下面的代码片段:

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
 => [] 

不应该返回a1和a2吗?
[#<A:0x000001009e2f18 @key=3>]

或者,我可能漏掉了什么...
1个回答

9
不,为了让Array#&Array#|正常工作,您需要实现哈希相等性(仅使用普通比较无法实现,复杂度为O(n * m))。注意,Array#|返回的结果也是错误的:它包含重复项。

可以通过以下方式实现这种相等方法:

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

 alias eql? ==

此外,如果另一个对象没有回应#key,则您的 <= > 将失败。 == 不应该失败,如果无法比较两个对象,则应返回false。这也是其中一种方法,您不想使用 respond_to?,而是要使用 is_a?:您不希望电影等于书,因为它们恰好有相同的标题。
def <=>(other)
  @key <=> other.key if other.is_a? A
end

谢谢帮我解决问题... 我们在 #hash 中需要使用异或运算符吗,因为我是通过它的 #key 比较两个 A。我认为,我们只需要保留 @key.hash。 - Mohammad Khan
它会起作用,因为eql?无论如何都会被调用。异或只是为了避免与哈希键发生冲突。即使是def hash; 1; end也可以工作,但性能会很差。 - Mon ouïe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接