2014-11-02 55 views
2

所以我有一个类,其中我需要重写相等运算符。这并不难。但是除非my_obj.hash对于两个正在比较的对象是相等的,否则不会使用自定义相等运算符。所以我们需要重写散列()在Ruby中制作对象哈希的最佳方法是什么?

我有点卡住最好的方式来做到这一点。我的对象嵌入了另外三个对象实例。我的例子中看到,对于简单的实例瓦尔你可以只取瓦尔的哈希自己:

[var1, var2, var3].hash 

更具体地说,我班有实例瓦尔三个嵌入对象,我们姑且称之为:

一个 B1 B2

我的对象的

两个实例是相等如果

object1.B1 == object2.B1 && object1.B2 == object2.B2 || 
     object1.B1 == object2.B2 && object1.B2 == object2.B1 

在换句话说,COLLEC无论分配给哪个特定的变量,B1和B2都有相同的两个对象。

B1和B2也有自定义等式机制。

我只是不清楚重写hash()的最佳策略。

对不起,如果这个例子是抽象的,我试图避免发布很多代码。

回答

2

尝试使用Set而不是数组,因此顺序无关紧要。你必须有这条线在顶部:

require 'set' 

然后让含有对象集,并用它来帮助实现平等的经营者和哈希方法。我假设Set#散列行为正确,你可以在你的散列方法中使用它。设置#==可以用来简化您的相等运算符。

http://www.ruby-doc.org/stdlib-2.1.4/libdoc/set/rdoc/Set.html

+1

如果'B1'和'B2'是不可取的,我支持这种技术。你的'hash'方法就像'return Set [self.B1,self.B2] .hash'一样简单。 – 2014-11-02 02:01:16

-1

我假设散列值可以是任何对象,只要它在您的案例中的每个对象中都是唯一的。如果这种假设是正确的,那么定义对象hash()方法如何返回为数组,例如?

我不是100%清楚你想达到什么。但我已经解释了self.B1self.B2的顺序没有关系。那么这是一个可能性:

def hash 
    [self.B1.hash, self.B2.hash].sort 
end 

然后,你可以比较两个对象的hash()

(my_obj1.hash == my_obj2.hash) 
+2

-1。这严重违反了'hash'的合同。 'hash'指定返回一个'Integer'。 – 2014-11-02 01:52:05

+0

@JörgWMittag什么是“合同”?默认情况下,'hash()'返回Integer。所以,我同意任何通用库'hash()'必须返回Integer。但是当无论如何都试图重新实现'hash()'时,我只是认为可以修改它,只要它在框架内一致。如果他/她不喜欢它,那么他/他不会选择它。 – 2014-11-02 02:07:31

+2

合约是'hash' a)返回符合'to_int'约定的东西,b)两个相等的对象具有相同的'hash'值。您的执行违反了a)点,例如导致如下:'{StevesClass.new => nil}#TypeError:没有将数组隐式转换为整数。 '[StevesClass.new,StevesClass.new] .uniq#TypeError:没有将数组隐式转换为Integer'。 '[StevesClass.new,StevesClass.new] .hash#TypeError:没有将数组隐式转换为Integer'。 '需要'设置';设置[StevesClass.new,StevesClass.new]#TypeError:...'。 – 2014-11-02 03:13:54

1

是你的B1B2对象排序?如果是这样,这里是一个很容易实现的hash方法:

class MyClass 
    def hash 
    return [self.B1, self.B2].sort.hash 
    end 
end 

如果他们目前没有排序,它是没有意义的任何内在价值对它们进行排序,你可以永远只是排序object_id

class BClass 
    include Comparable 

    def <=> (other) 
    case other 
    when BClass then return (self.object_id <=> other.object_id) 
    else return nil 
    end 
    end 
end 

这使您B1B2对象自己解决与对方,而扔“引发ArgumentError:与Y X的比较失败”与任何其他类的实例。

如果你打算使用object_id的路线,虽然,它可能是更容易使用,开始与实现你hash方法:

class MyClass 
    def hash 
    return [self.B1.object_id, self.B2.object_id].sort.hash 
    end 
end 

,但是这将意味着只有自相同的对象会正确地变得平等,而不仅仅是“看起来”相似的物体。要理解我的意思,请比较以下内容:

# Comparison of look-alike objects 
"a".object_id == "a".object_id # => false 

# Comparison of self-same objects 
a = "a" 
a.object_id == a.object_id  # => true 
+0

你是我最喜欢的Rubyist之一.. – 2014-11-02 12:03:27

相关问题