2014-09-27 33 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