在HashSet中使用替代比较

时间:2009-07-27 19:45:48

标签: scala hash equals

在创建HashSet [Array [Byte]]以在一种HatTrie中使用时,我偶然发现了这个问题。

显然,数组上的标准equals()方法检查身份。如何为HashSet提供另一个使用.deepEquals()来检查集合中是否包含元素的Comparator?

基本上,我希望这个测试通过:

describe ("A HashSet of Byte Array") {      

    it("must contain arrays that are equivalent to one that has been added") {
        val set = new HashSet[Array[Byte]]()
        set += "ab".getBytes("UTF-8")
        set must contain ("ab".getBytes("UTF-8"))           
    }
}

我无法将Array [Byte]包装到另一个对象中,因为它们有很多。如果没有为此目的编写新的HashSet实现,我还能做些什么吗?

1 个答案:

答案 0 :(得分:1)

在使用哈希码的地方使用可变数据结构(如数组)是禁忌的。这是因为数据结构可以改变,从而改变数据的哈希码,从而使得访问数据不准确。

例如,假设我有一个二叉树来存储基于其哈希码的元素。如果哈希是偶数,我将数据存储在左侧,如果是奇数则存储在右侧。然后我将散列除以2,并重复该过程,直到散列为0,此时我将数据存储在节点中。

现在,我使用此结构作为HashSet的基础,然后在其上存储数组。该数组具有偶数哈希码,因此它将转到树的左侧。让我们忽略它的确切位置。

稍后,我更改了数组,然后在集上查找。现在哈希码是奇怪的,我去查看树的右侧,因此无法找到它,即使它存储在树中 - 只是在另一侧。

因此,不要将数组与基于散列的集合一起使用。当然,这不能回答你的问题。

至于你的问题,你必须继承HashSet,然后覆盖equals方法。我不知道HashSet是密封类的最终还是后代,所以我不知道这是否可行。

另一种选择是创建一个替代的比较方法 - 不是名为equals或“==”,特别是基于deepEquals,然后使用Pimp My Class方法将其添加到HashSet。

修改

我的意思是子类HashSet,但我对这个问题没有给予足够的重视。我以为你是在比较整个HashSet,而不仅仅是使用contains。你可以这样做:

class MyHashSet[A] extends scala.collection.mutable.HashSet[A] {
  override def contains(elem: A): Boolean = elem match {
    case arr : Array[_] => this.elements exists (arr deepEquals _)
    case _ => super.contains(elem)
  }
}

这实际上并没有在这里工作,因为没有遵循第一个案例。我真的迷失在这里,因为对REPL的简单测试似乎表明它应该有效。我认为它可能与拳击有关,但我不清楚什么 - 或者我有它的工作。 : - )