2014-09-27 35 views
1

我已經實現了我的多鍵類如下:HashMap上的多個鍵:它刪除現有的值?

public class ProbabilityIndex { 

    private int trueLabel; 
    private int classifiedLabel; 
    private int classifierIndex; 

    public ProbabilityIndex(int trueLabel, int classifiedLabel, int classifierIndex) { 
     this.trueLabel = trueLabel; 
     this.classifiedLabel = classifiedLabel; 
     this.classifierIndex = classifierIndex; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (!obj instanceof ProbabilityIndex) 
      return false; 
     if (obj == this) 
      return true; 

     ProbabilityIndex rhs = (ProbabilityIndex) obj; 
     return new EqualsBuilder(). 
      append(trueLabel, rhs.trueLabel). 
      append(classifiedLabel, rhs.classifiedLabel). 
      append(classifierIndex, rhs.classifierIndex). 
      isEquals(); 

    } 

    @Override 
    public int hashCode() { 
     int hashCode = new HashCodeBuilder(17, 31). 
       append(trueLabel). 
       append(classifiedLabel). 
       append(classifierIndex). 
       toHashCode(); 
     return hashCode; 
    } 
} 

注意trueLabelclassifiedLabelclassifierIndex均爲0或1

然後,我用我的鑰匙如下:

ProbabilityIndex key = new ProbabilityIndex(trueLabel, classifiedLabel, classifierIndex); 
probabilities.put(key, new Double(value)); 

其中probabilities聲明如下:

HashMap<ProbabilityIndex, Double> probabilities; 

但是,trueLabel,classifiedLabelclassifierIndex的不同組合將該元組寫入probabilities中的相同位置,從而覆蓋現有的元組。

我該如何解決這個問題?

最少測試用例:

HashMap<ProbabilityIndex, Double> map = new HashMap<ProbabilityIndex, Double>(); 
    map.put(new ProbabilityIndex(0, 0, 0), new Double(0.1)); 
    map.put(new ProbabilityIndex(0, 0, 1), new Double(0.2)); 
    map.put(new ProbabilityIndex(0, 1, 0), new Double(0.1)); 
    map.put(new ProbabilityIndex(0, 1, 1), new Double(0.2)); 
    map.put(new ProbabilityIndex(1, 0, 0), new Double(0.1)); 

這將插入4元組,而不是5

+2

你可以構造一個[minimal test-case](http://stackoverflow.com/help/mcve)來證明這一點嗎? – 2014-09-27 17:14:45

+0

什麼是EqualsBuilder? – SJha 2014-09-27 17:15:28

+0

@SJha:https://www.google.co.uk/search?q=equalsbuilder – 2014-09-27 17:17:14

回答

3

我只能告訴你,哈希表絕不會覆蓋具有相同散列碼的對象(一哈希碰撞);它的檢索效率會降低。

錯誤地覆蓋輸入的唯一方法是爲密鑰提供equals方法,該方法爲不同的密鑰返回true

一些進一步的建議與您的問題沒有直接關係:如果您擁有的是三個雙態變量,那麼爲該類設置的完整值只有8的基數。而不是使用複雜的散列碼構建器,你可以用三位構造哈希碼,每個代表一個變量。這將清楚地確保您的對象的每個狀態都有明確的哈希代碼。

我已經驗證了你的代碼的hashCode()equals()以下實現(我不得不改變equals使你的榜樣真正自足):

@Override public boolean equals(Object obj) { 
    if (!(obj instanceof ProbabilityIndex)) return false; 
    if (obj == this) return true; 
    ProbabilityIndex rhs = (ProbabilityIndex) obj; 
    return this.trueLabel == rhs.trueLabel 
     && this.classifiedLabel == rhs.classifiedLabel 
     && this.classifierIndex == rhs.classifierIndex; 
} 

@Override public int hashCode() { 
    return trueLabel | (classifiedLabel << 1) | (classifierIndex << 2); 
} 

你的測試代碼導致了有五個表項的地圖。

最後一點,如果最大大小隻有8個,你甚至不需要散列表。一個由上述散列碼索引的8的普通數組就足夠了。

+0

您的建議散列碼解決了這個問題。所以,我猜我的函數產生了一致的hashcode。 – Eleanore 2014-09-27 17:39:12

+2

不,正如我在答案中解釋的那樣,哈希碼衝突無法重現您的問題。要說服自己,請使用'public int hashCode(){return 1; }'。 – 2014-09-27 17:41:05

+0

因此,代碼中equals方法的代碼相同的問題在哪裏出現。前代碼使用常見的lang api,並使用直接代碼。但是兩個代碼都是一樣的。 – Hansraj 2014-09-27 17:46:40