Множественные ключи к единой карте значений Java

Я думаю, что мой вопрос похож на этот: Как реализовать карту с несколькими ключами?, но с важным отличием. В этом вопросе (если мое понимание этого правильное, сообщите мне, если это не так), ключи должны были всегда быть уникальными. Я хочу иметь карту в форме: MyMap где ключи не обязательно уникальны. Если это не имеет смысла, я в основном хочу 2-мерный массив, но вместо того, чтобы ссылаться на элементы по координатам, я хочу ссылаться на них парами объектов.

У кого-нибудь есть идеи относительно библиотеки, где это работает, или хорошего способа реализовать это самостоятельно? Что касается библиотек, я смотрел Apache Commons и Guava, у меня, похоже, не было того, что я хочу.

Ответ 1

Структура Table в Гуаве, по-видимому, отвечает вам требованием ссылаться на значение парой объектов.

Ответ 2

Я надеюсь, что этот ответ не будет рассматриваться как раскаяние, но, насколько я понял, вы хотите использовать библиотеку для чего-то, что вы можете достичь тривиально, используя jdk из коробки.

В любом случае вы упомянули, что хотите получить доступ к элементам, используя пару объектов. Вы можете создать класс, в котором будут храниться ключи, например

public class Pair {
  // string represntation of an object
  private final String x; 
  private final String y;

  // ctor, getters...

  public int hashcode() {...}
  public boolean equals(Object other) {...}
}

Метод hashcode будет генерировать хэш-код для всех содержащихся элементов (в данном случае два, x и y в вашем случае, но может быть легко расширен для поддержки произвольного количества элементов) и два ключи будут одинаковыми, если они имеют одинаковые значения для x и y. Если элементы пары не являются простыми строками, тривиально выводить строковое представление почти любого объекта (например, обеспечить достойную реализацию метода toString).

Идея состоит в том, чтобы иметь уникальное строковое представление для каждого элемента в паре.

Конечно, создание твердых хэш-кодов не является тривиальным, поэтому отличным вариантом является использование строк. Чтобы создать хэш-код, вы просто добавите строковые представления ваших парных объектов:

public int hashcode() {
  return ('x' + x + ":y" + y).hashcode();
}

Обязательно укажите разделитель. В противном случае для таких значений, как x=ab, y=b и x=a, y=bb, вы получите тот же хэш-код, даже если объекты полностью разные.

И равенство так же тривиально, как проверка значения элементов в паре:

public boolean equals(Object other) {
  // if other is not null and is an instance of Pair
  final Pair otherPair = (Pair)other;
  return this.x.equals(otherPair.x) && this.y.equals(otherPair.y);
}

Итак, теперь вы можете использовать свой класс Pair на карте, например, в:

final Map<Pair, Whatever> map = new Hashmap<Pair, Whatever>();
// ...

В основном, hashmap работает, используя хэш-код ключей, чтобы определить, в каком ведре должно быть выделено значение. Если два ключа имеют один и тот же хэш-код, то метод equals будет использоваться для определения того, произошло ли только столкновение, или если это только тот же ключ.

Если вы хотите использовать класс Pair в TreeMap, вам придется реализовать метод compareTo или предоставить свой собственный Comparator при создании такой карты. TreeMap реализация полагается на результат метода compareTo, чтобы определить, где должно быть выделено значение.

Ответ 3

Мне кажется, что вы ищете вложенный HashMap. Это может сработать, но мой взгляд говорит, что внедрение такого монстра будет ужасной идеей, как разумной, так и разумной.

Как вы могли бы его инициализировать:

    HashMap<Key1, HashMap<Key2, Value>> nestedHashMap = new HashMap<Key1, HashMap<Key2, Value>>();

Добавление значений:

    Key1 first;
    Key2 second;
    Value data;
    HashMap<Key2, Value> tempMap = new HashMap<Key2, Value>();
    tempMap.put(second, data);
    nestedHashMap.put(first, tempMap);

Получение данных:

    Key1 first;
    Key2 second;
    Value data;
    data = nestedHashMap.get(first).get(second);

Отказ от ответственности: этот код не был протестирован, он просто сошел с моей головы.

Ответ 4

Коллекции коллекций Apache имеют MultiKey.

import org.apache.commons.collections4.keyvalue.MultiKey;

Map<MultiKey, ValueType> myMap = new HashMap<MultiKey, ValueType>();
myMap.put(new MultiKey(key1, key2), value);

myMap.get(new MultiKey(key1, key2));

Это позволяет создавать N-мерные массивы с карты.