Ruby Set class: equality of sets

According to the documentation of the Ruby Set class, "== Returns true if the two sets are equal. The equality of each pair of elements is determined according to Object # eql ?.

The essence of this can be demonstrated using Date objects, where sets containing different Date objects but with the same date are compared with equal:

require 'set' d1 = Date.today # => Thu, 30 Sep 2010 puts d1.object_id # => 2211539680 d2 = Date.today + 1 # => Fri, 01 Oct 2010 puts d2.object_id # => 2211522320 set1 = Set.new([d1, d2]) d11 = Date.today # => Thu, 30 Sep 2010 puts d11.object_id # => 2211489080 d12 = Date.today + 1 # => Fri, 01 Oct 2010 puts d12.object_id # => 2211469380 set2 = Set.new([d12, d11]) set1 == set2 # => true 

But using my own objects, where did I code eql? a method to compare only certain attributes, I cannot get it to work.

 class IpDet attr_reader :ip, :gateway def initialize(ip, gateway, netmask, reverse) @ip = ip @gateway = gateway @netmask = netmask @reverse = reverse end def eql?(other) if @ip = other.ip && @gateway == other.gateway return true else return false end end end ipdet1 = IpDet.new(123456, 123457, 123458, 'example.com') ipdet2 = IpDet.new(234567, 2345699, 123458, 'nil') ipdet11 = IpDet.new(123456, 123457, 777777, 'other_domain.com') ipdet12 = IpDet.new(234567, 2345699, 777777, 'example.com') puts "ipdet1 is equal to ipdet11: #{ipdet1.eql?(ipdet11)}" puts "ipdet2 is equal to ipdet12: #{ipdet2.eql?(ipdet12)}" set1 = Set.new([ipdet1, ipdet2]) set2 = Set.new([ipdet11, ipdet12]) puts "set 1 is equal to set2: #{set1 == set2}" 

Exit from the above:

 ipdet1 is equal to ipdet11: true ipdet2 is equal to ipdet12: true set 1 is equal to set2: false 

Any ideas anybody?

+4
source share
1 answer

When do you redefine eql? , you also need to redefine hash so that if o1.eql?(o2) true, then o1.hash == o2.hash .

For example, your hash method might look like this:

 def hash [@ip, @gateway].hash end 

Also do you have a typo in the eql? method eql? : @ip = other.ip should be @ip == other.ip .

Also small stylenote: if condition then true else false end equivalent to just condition , so your eql? method eql? can simply be defined as

 def eql?(other) @ip == other.ip && @gateway == other.gateway end 
+10
source

All Articles