Класс Ruby Set: равенство множеств - PullRequest
4 голосов
/ 30 сентября 2010

Согласно документации класса Ruby Set, "== Возвращает true, если два набора равны. Равенство каждой пары элементов определяется в соответствии с Object # eql?.

Суть этого может бытьпродемонстрировано использование объектов Date, где наборы, содержащие разные объекты Date, но с одинаковой датой, сравниваются с равными:

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

Но используя мои собственные объекты, где я кодировал метод eql? для сравнения только определенных атрибутовЯ не могу заставить его работать.

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}"

Вывод, который я получаю из вышесказанного:

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

Есть идеи у кого-нибудь?

1 Ответ

11 голосов
/ 30 сентября 2010

Когда вы переопределяете eql?, вам также всегда нужно переопределить hash так, чтобы, если o1.eql?(o2) было истиной, o1.hash == o2.hash также было истиной.

Например, ваш хэш-метод может выглядеть так:

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

Также в вашем методе eql? есть опечатка: @ip = other.ip должно быть @ip == other.ip.

Также второстепенный стилот: if condition then true else false end эквивалентен просто condition, поэтому ваш метод eql? можно просто определить как

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