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

f1equalsf2であるため、両方を含めるsべきではありません。

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

Ruby プログラミング言語の本 (Ruby 言語の作成者である松本幸宏氏と共著) によると、ハッシュ メソッドの汎用レシピには、いくつかの数値 (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 に答える