镶嵌在红宝石中如何比较元素?

时间:2018-11-20 18:29:10

标签: ruby set

我正在尝试将自定义对象放入集合中。我尝试过:

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

似乎Set不能使用Object#eql?==方法标识相同的对象:

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

Set如何识别两个相同的对象?

2 个答案:

答案 0 :(得分:5)

来自docs

  

Set使用Hash作为存储,因此必须注意以下几点:

     
      
  • 元素的相等性是根据Object#eql?Object#hash确定的。 [...]
  •   

那是说:如果您希望两个人在同名时是平等的,那么您必须相应地实现hash

def hash
  @name.hash
end

答案 1 :(得分:3)

Ruby的内置Set将项目存储在Hash中。因此,对于Set将对象视为“相同”的对象,还需要定义一个自定义hash方法。这样的事情会起作用:

def hash
  @name.hash
end

使用gem which set.rb查看Set的源代码的存储位置,然后尝试通读它。它很清楚而且写得很好。