HashMap上的多个键:删除现有值?

时间:2014-09-27 17:10:45

标签: java hashmap key

我已经实现了我的多个密钥类,如下所示:

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;

但是,trueLabelclassifiedLabelclassifierIndex的不同组合会将元组写入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个。

1 个答案:

答案 0 :(得分: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的普通数组,用上面的哈希码索引,就足够了。

相关问题