5

根据Set doc,集合中的元素使用eql?.

我有一个像这样的课程:

class Foo
  attr_accessor :bar, :baz

  def initialize(bar = 1, baz = 2)
    @bar = bar
    @baz = baz
  end

  def eql?(foo)
    bar == foo.bar && baz == foo.baz
  end
end

在控制台中:

f1 = Foo.new
f2 = Foo.new
f1.eql? f2 #=> true

但...

 s = Set.new
 s << f1
 s << f2
 s.size #=> 2

因为f1equals f2s应该同时包含它们。

如何set使用自定义规则制作拒绝元素?

4

2 回答 2

7

您链接到的文档明确说明(强调我的):

每对元素的相等性根据Object#eql?
Object#hash确定,因为Set用作Hash存储。

如果您hash向类中添加一个为对象返回相同值的方法eql?,它会起作用:

# With your current class

f1, f2 = Foo.new, Foo.new
p f1.eql?(f2)
#=> true
p f1.hash==f2.hash
#=> false
p Set[f1,f2].length
#=> 2

# Fix the problem
class Foo
  def hash
    [bar,hash].hash
  end
end

f1, f2 = Foo.new, Foo.new
p f1.eql?(f2)
#=> true
p f1.hash==f2.hash
#=> true
p Set[f1,f2].length
#=> 1

老实说,当涉及多个值时,我对如何编写一个好的自定义方法从来没有很好的理解。hash

于 2012-04-14T13:27:07.947 回答
0

根据 The Ruby Programming Language 一书(由 Ruby 语言创建者 Yukihiro Matsumoto 合着),哈希方法的通用配方涉及一些数字 (17/37) 常量的使用。对于给定的示例,建议的解决方案如下:

def hash
  code = 17
  code = 37*code + @bar.hash
  code = 37*code + @baz.hash
  code
end

所以一般来说,我们为每个重要的实例变量 (@x) 重复“code = 37*code + @x.hash”行。

于 2014-04-01T09:17:35.057 回答