2009-07-27 44 views
3

當創建HashSet [Array [Byte]]以在一種HatTrie中使用時,我偶然發現了這個問題。在HashSet中使用替代比較

顯然,數組上的標準equals()方法檢查身份。我怎樣才能提供一個替代比較器使用.deepEquals()檢查是否包含一個元素的HashSet?

基本上,我希望這個測試通過:

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"))   
    } 
} 

我不能切實包裹陣列(字節)到另一個對象,因爲有很多他們。爲此目的而編寫新的HashSet實現的方法有什麼我可以做的嗎?

回答

1

可變數據結構(如陣列)在使用哈希碼的地方使用時被禁用。這是因爲數據結構可能會改變,從而改變數據的哈希碼,從而使訪問數據不準確。

例如,假設我有一個二叉樹來存儲基於哈希碼的元素。如果哈希值是偶數,我將數據存儲在左側,如果奇數在右側。然後我將散列除以2,然後重複該過程,直到散列爲0,此時我將數據存儲在節點中。

現在,我使用這個結構作爲HashSet的基礎,然後在其上存儲一個數組。該數組有一個偶數散列碼,所以它會到樹的左側。讓我們忽略它的確切位置。

後來,我改變了數組,然後在集上查找它。現在散列碼很奇怪,我去看樹的右邊,因此找不到它,即使它存儲在樹中 - 就在另一邊。

因此,不要使用帶有基於散列的集合的數組。當然,這並不能回答你的問題。

至於你的問題,你必須繼承HashSet,然後重寫equals方法。我不知道HashSet是否是封閉類的最後或後代,所以我不知道這是否可行。

另一種選擇是創建一個替代的比較方法 - 不是根據deepEquals命名爲equals或「==」,然後使用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的簡單測試似乎表明它應該起作用。我認爲這可能與拳擊有關,但我不清楚什麼 - 或者我有它的工作。 :-)

+0

您當然對正在依賴訂購的可變數據結構和容器的危險組合是正確的。我只是在原型中嘗試這個,並想知道是否有一種快速的方法來使它工作。這似乎並非如此。我想正確的解決方案將是創建一個類,它實現了一個不變的字節數組和一個我需要的equals方法。 – 2009-07-27 20:26:39