Ruby:集合中对象的重复值

时间:2014-05-01 01:42:08

标签: ruby-on-rails ruby set

我在Ruby中有一个集合,它将保存我创建的类的对象。我正在使用该集来防止重复值,但我仍然在集合中获得重复值。假设它是因为集合中的对象,即使它们具有相同的值,它们也具有不同的地址。以下是我的内容:

sample_set = Set.new

sample_set的当前输出:

{
    #<SampleModule: : SampleClass: 0x007fba92923ae8@name="Hello World!",
    @id=123>,
    #<SampleModule: : SampleClass: 0x007fba92922fd0@name="Hello World!",
    @id=123>,
    #<SampleModule: : SampleClass: 0x007fba92922418@name="Star Wars",
    @id=456>,
    #<SampleModule: : SampleClass: 0x007fba929217c0@name="Star Wars",
    @id=456>,
    #<SampleModule: : SampleClass: 0x007fba92920ac8@name="Star Wars",
    @id=456>
} 

sample_set的预期输出:

{
    #<SampleModule: : SampleClass: 0x007fba92923ae8@name="Hello World!",
    @id=123>,
    #<SampleModule: : SampleClass: 0x007fba929217c0@name="Star Wars",
    @id=456>
}

是否有可能在红宝石中实现这一目标?我们是否需要覆盖'eql'方法来执行此操作?

解决方案:

def eql?(other)
  other.instance_of?(self.class) && @name == other.name && @id == other.id
end

def hash
  @name.hash ^ @id.hash
end

1 个答案:

答案 0 :(得分:3)

(从上面的评论中移出)

你可能没有覆盖#hash和#eql?在您的SampleClass中。为了使哈希和集合等数据结构正常工作,您需要这样做。

编程语言具有对象相等的概念,通常由某种等式函数和散列函数(Ruby中的eql?和hash)组成。该语言使用相等函数来确定两个对象是否相等。散列函数为某些数据结构(如集合和散列表)使用的每个对象计算散列(唯一值)。重要的是,如果两个对象相等(就eql而言?),必须具有相同的哈希值,否则哈希表和集将无法正常运行。

我的Ruby有点生疏,但对于SampleClass来说可能看起来像这样:

class SampleClass
   ...
   def eql? other
      other.instance_of?(self.class) 
         && @id == other.id
         && @name == other.name
   end

   # delegate to hash function of whatever primitive @id and @name are
   # probably Fixnum and String?
   # Uses two prime numbers, adapted from Effective Java by Joshua Bloch
   def hash 
      p, q = 17, 37
      p = q * @id.hash
      p = q * @name.hash
   end
   ...
end