Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Set in ruby compare elements?

Tags:

ruby

set

I am trying to put custom objects in a set. I tried this:

require 'set'

class Person
  include Comparable

  def initialize(name, age)
    @name = name
    @age = age
  end
  attr_accessor :name, :age

  def ==(other)
    @name == other.name
  end
  alias eql? ==
end

a = Person.new("a", 18)
b = Person.new("a", 18)
people = Set[]
people << a
people << b

puts a == b # true

It seems that Set does not identify same objects with Object#eql? or == methods:

puts people # #<Set: {#<Person:0x00007f9e09843df8 @name="a", @age=18>, #<Person:0x00007f9e09843da8 @name="a", @age=18>}>

How does Set identify two same objects?

like image 382
YiLuo Avatar asked Sep 20 '26 23:09

YiLuo


2 Answers

From the docs:

Set uses Hash as storage, so you must note the following points:

  • Equality of elements is determined according to Object#eql? and Object#hash. [...]

That said: If you want two people to be equal when they have the same name, then you must implement hash accordingly:

def hash
  @name.hash
end
like image 55
spickermann Avatar answered Sep 24 '26 06:09

spickermann


Ruby's built-in Set stores items in a Hash. So for your objects to be treated as the "same" by Set, you also need to define a custom hash method. Something like this would work:

def hash
  @name.hash
end

Use gem which set.rb to see where the source code for Set is stored, and try reading through it. It's clear and well-written.

like image 30
Alex D Avatar answered Sep 24 '26 08:09

Alex D



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!