如何为包含可比较的类定义哈希函数?

Pad*_*i91 5 ruby hash comparable

想象一下包括类似这样的类:

class Element
  include Comparable
  attr_accessor :name, :pos_x, :pos_y

  def initialize(name, pos_x, pos_y)
    @name = name
    @pos_x = pos_x
    @pos_y = pos_y
  end

  def <=>(other)
    if (@pos_x == other.pos_x) and (@pos_y == other.pos_y)
      return 0
    else 
      return @name <=> other.name
    end
  end

  def eql?(other)
    self == other
  end
end
Run Code Online (Sandbox Code Playgroud)

在这种情况下hash,你将如何实现这个功能a.hash == b.hash?一般来说,我会这样做:

def hash
  @name.hash
end
Run Code Online (Sandbox Code Playgroud)

但这不包括pos_xpos_y.

Bro*_*tse 1

不幸的是,在这种情况下,在数学上不可能定义有效的哈希函数。

设a、b是位置相同、名称不同的两个元素。根据eql?定义,这意味着h(a) == h(b). 由于这对于任何名称值都是如此,因此散列函数将独立于名称属性,但这与第二个检查相矛盾。因此,这个定义没有哈希函数eql?。对不起。:(

更新:

正如 toro2k 所指出的 - 你的平等定义是不可传递的。一般来说,如果a == b且b == c,则要求a == c。根据你的eql?功能:

{pos_x: 1, pos_y: 1, name: 'a'} == {pos_x: 1, pos_y: 1, name: 'b'}
{pos_x: 1, pos_y: 1, name: 'b'} == {pos_x: 2, pos_y: 2, name: 'b'}
Run Code Online (Sandbox Code Playgroud)

{pos_x: 1, pos_y: 1, name: 'a'} != {pos_x: 2, pos_y: 2, name: 'b'}
Run Code Online (Sandbox Code Playgroud)

这就是你问题的根源。