Многозначная хеш-таблица в Java - PullRequest
25 голосов
/ 26 июня 2009

Можно ли иметь несколько значений для одного и того же ключа в хэш-таблице? Если нет, можете ли вы предложить какой-либо такой класс или интерфейс, который можно использовать?

Ответы [ 13 ]

21 голосов
/ 26 июня 2009

Нет. Это своего рода идея хеш-таблиц.

Однако вы можете либо свернуть свой собственный с Map<YourKeyObject, List<YourValueObject>> и некоторыми вспомогательными методами для создания списка, если его нет, либо использовать что-то вроде Multimap из Google Collections .

Пример:

String key = "hello";
Multimap<String, Integer> myMap = HashMultimap.create();
myMap.put(key, 1);
myMap.put(key, 5000);
System.out.println(myMap.get(key)); // prints either "[1, 5000]" or "[5000, 1]"
myMap = ArrayListMultimap.create();
myMap.put(key, 1);
myMap.put(key, 5000);
System.out.println(myMap.get(key)); // always prints "[1, 5000]"

Обратите внимание, что Multimap не является точным эквивалентом домашнего выпекаемого раствора; Hashtable синхронизирует все его методы, в то время как Multimap не дает такой гарантии. Это означает, что использование Multimap может вызвать проблемы , если вы используете его в нескольких потоках . Если ваша карта используется только в одном потоке, это не будет иметь значения (и вы должны были использовать HashMap вместо Hashtable в любом случае).

11 голосов
/ 26 июня 2009

Значения хеш-таблицы - Object, поэтому вы можете хранить список

7 голосов
/ 26 июня 2009

В хеш-таблице можно использовать пару ключ / значение для хранения информации.

В Java класс Hashtable принимает одно значение для одного ключа. Ниже приведен пример попытки связать несколько значений с одним ключом:

Hashtable<String, String> ht = new Hashtable<String, String>();

ht.put("Answer", "42");
ht.put("Hello", "World");    // First value association for "Hello" key.
ht.put("Hello", "Mom");      // Second value association for "Hello" key.

for (Map.Entry<String, String> e : ht.entrySet()) {
  System.out.println(e);
}

В попытке включить несколько значений ("World", "Mom") в одну клавишу ("Hello") мы получаем следующий результат для печати записей в Hashtable:

Answer=42
Hello=Mom

Пара ключ / значение "Hello" и "World" отсутствует в Hashtable - только вторая запись "Hello" и "Mom" находится в Hashtable. Это показывает, что нельзя иметь несколько значений, связанных с одним ключом в Hashtable.


Здесь действительно требуется multimap , который позволяет связать несколько значений с одним ключом.

Одна реализация мультикарты - Multimap из Google Collections :

Multimap<String, String> mm = HashMultimap.create();

mm.put("Answer", "42");
mm.put("Hello", "World");
mm.put("Hello", "Mom");

for (Map.Entry<String, String> e : mm.entries()) {
  System.out.println(e);
}

Это похоже на приведенный выше пример, в котором используется Hashtable, но поведение совершенно иное - Multimap позволяет связать несколько значений с одним ключом. Результат выполнения вышеуказанного кода выглядит следующим образом:

Answer=42
Hello=Mom
Hello=World

Как видно, для клавиши "Hello" значения "Mom" и "World" связаны с ней. В отличие от Hashtable, оно не сбрасывает одно из значений и не заменяет его другим. Multimap может удерживать несколько значений для каждой клавиши.

7 голосов
/ 26 июня 2009

Вместо того, чтобы дать еще один многостраничный ответ, я спрошу, почему вы хотите это сделать?

Связаны ли множественные значения? Если да, то, вероятно, лучше создать структуру данных для их хранения. Если нет, то, возможно, более уместно использовать отдельные карты.

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

5 голосов
/ 26 июня 2009

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

Библиотека Google Collections ( update : Guava ) содержит одну реализацию и, вероятно, является лучшим выбором.

Редактировать : конечно, вы можете сделать так, как Эрик предлагает , и сохранить коллекцию как значение в вашей Hashtable (или карте, в более общем смысле), но это означает написание ненужного шаблонного примера. закодируй себя При использовании библиотеки, такой как Google Collections, она позаботится о низкоуровневой «сантехнике» для вас. Посмотрите этот хороший пример того, как ваш код может быть упрощен при использовании Multimap вместо классных классов Java Collections.

4 голосов
/ 27 июня 2009

Просто сделай свой собственный:

Map<Object, List<Object>> multiMap = new HashMap<Object, List<Object>>();

Добавить:

  public void add(String key, Object o) {
    List<Object> list;
    if (multiMap.containsKey(key)) {
      list = multiMap.get(key);
      list.add(o);
    } else {
      list = new ArrayList<Object>();
      list.add(o);
      multiMap.put(key, list);
    }
  }
4 голосов
/ 26 июня 2009

Ни в одном из ответов не указано, что я сделаю первым.

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

Почти все время я обнаруживаю связь между объектами, которые пытаюсь поместить в хеш-таблицу. Чаще всего, есть место для класса - даже метод или два.

На самом деле, я часто нахожу, что мне даже не нужна структура типа HashMap - простой HashSet подходит.

Элемент, который вы храните в качестве первичного ключа, может стать идентификатором нового объекта - так что вы можете создать методы равенства и хэширования, которые ссылаются только на этот один объект (затмение может легко сделать ваши методы равенства и хэширования для вас). таким образом новый объект будет сохранять, сортировать и извлекать в точности так, как это делал ваш исходный объект, а затем использовать свойства для хранения остальных элементов.

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

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

2 голосов
/ 26 июня 2009

То, что вы ищете, это Multimap . API коллекций Google API обеспечивает хорошую реализацию этого и многого другого, чему стоит научиться пользоваться. Настоятельно рекомендуется!

2 голосов
/ 26 июня 2009

См. Библиотеку коллекций Google для мультикарт и подобных подобных коллекций. Встроенные коллекции не имеют прямой поддержки для этого.

1 голос
/ 26 июня 2009

Simple. Вместо Hashtable<Key, Value>, используйте Hashtable<Key, Vector<Value>>.

...