Set using a special rule

According to Set doc, the elements in the set are compared using eql?.

I have a class like:

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

In the console:

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

But...

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

Because f1equal f2, sshould not include both of them.

How to make setreject items using a custom rule?

+5
source share
2 answers

The documents you are referencing clearly indicate (my attention):

The equality of each pair of elements is determined according to Object#eql?
andObject#hash , since it is Setused Hashas storage.

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 , .

+7

Ruby ( Yukihiro Matsumoto, Ruby) - (17/37). :

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

, "code = 37 * code + @x.hash" (@x).

0

All Articles