Карта с несколькими ключами на одно значение 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);

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

Другие вопросы по тегам