Карта с несколькими ключами на одно значение Java
Я думаю, что мой вопрос похож на этот: как реализовать карту с несколькими ключами? но с важным отличием. В этом вопросе (если я правильно понимаю, пожалуйста, дайте мне знать, если это не так), ключи должны были быть уникальными. Я хочу иметь карту в виде:MyMap, где ключи не обязательно уникальны. Если это не имеет смысла, я в основном хочу двумерный массив, но вместо ссылки на элементы по координатам я хочу ссылаться на них по парам объектов.
У кого-нибудь есть какие-либо идеи относительно библиотеки, где это работает, или хорошего способа реализовать это самостоятельно? Что касается библиотек, я смотрел на Apache Commons и Guava, и, похоже, у меня нет того, чего я хочу.
4 ответа
Кажется, что структура данных таблиц в Гуаве соответствует требованию ссылки на значение парой объектов.
Я надеюсь, что этот ответ не будет воспринят как пустяк, но насколько я понимаю, вы хотите использовать библиотеку для чего-то, чего вы можете достичь тривиальным способом, используя 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
метод, например).
Идея состоит в том, чтобы иметь уникальное строковое представление для каждого элемента в паре.
Конечно, создание твердых хэш-кодов не является тривиальным, поэтому отличный вариант - использовать Strings. Чтобы сгенерировать хеш-код, вы просто добавите строковые представления ваших парных объектов:
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>();
// ...
По сути, хэш-карта работает с использованием хэш-кода ключей, чтобы определить, в каком сегменте следует разместить значение. Если два ключа имеют одинаковый хэш-код, то метод equals будет использоваться для определения того, произошло ли только что столкновение или это просто один и тот же ключ.
Если вы хотите использовать свой Pair
класс в TreeMap
, вам придется реализовать compareTo
метод, или предоставить свой собственный Comparator
при создании такой карты. TreeMap
реализации полагаются на результат compareTo
метод, чтобы определить, где значение должно быть выделено.
Коллекции Apache Commons имеют 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-мерных массивов из карты.
Для меня это звучит так, будто вы ищете вложенный 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);
Отказ от ответственности: этот код не был проверен, он просто пришелся мне в голову.