Несколько ключей на HashMap: он удаляет существующие значения?

1

Я выполнил свой класс с несколькими ключами следующим образом:

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;
    }
}

Обратите внимание на то, что trueLabel, classifiedLabel и classifierIndex все 0 или 1.

Затем я использую свой ключ следующим образом:

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

где probabilities объявляются следующим образом:

HashMap<ProbabilityIndex, Double> probabilities;

Тем не менее, различные комбинации trueLabel, classifiedLabel и classifierIndex написать кортеж в том же самом положении в 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
    Можете ли вы построить минимальный тест-кейс, который демонстрирует это?
  • 0
    Что такое EqualsBuilder?
Показать ещё 3 комментария
Теги:
key
hashmap

1 ответ

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
    Ваш предложенный хэш-код решил проблему. Итак, я предполагаю, что моя функция генерировала совпадающие хэш-коды.
  • 2
    Нет, как я объясняю в ответе, коллизия хеш-кода не может воспроизвести вашу проблему. Чтобы убедиться в этом, попробуйте код с public int hashCode() { return 1; }
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню