Карта с двумерным ключом в Java - PullRequest
22 голосов
/ 16 июня 2011

Мне нужна карта, проиндексированная двумя ключами (карта, в которую вы помещаете И извлекаете значения, используя два ключа) в Java. Просто чтобы прояснить, я ищу следующее поведение:

map.put(key1, key2, value); 
map.get(key1, key2); // returns value
map.get(key2, key1); // returns null
map.get(key1, key1); // returns null

Какой лучший способ это сделать? Более конкретно, я должен использовать:

  • Map<K1,Map<K2,V>>

  • Map<Pair<K1,K2>, V>

  • Другое

(где K1, K2, V - типы первого ключа, второго ключа и значения соответственно)

Ответы [ 7 ]

37 голосов
/ 16 июня 2011

Вы должны использовать Map<Pair<K1,K2>, V>

  1. Она будет содержать только одну карту вместо N + 1 карт

  2. Создание ключа будеточевидно (создание пары)

  3. Никто не запутается в значении карты, поскольку ее программист, обращенный к API, не изменится.

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

15 голосов
/ 16 июня 2011

Если вы хотите принести новую библиотеку (которую я рекомендую), взгляните на Таблица в Гуава .По сути, это делает именно то, что вы ищете, также возможно добавление некоторой функциональности, когда вы можете захотеть, чтобы все записи соответствовали одному из ваших двух ключей.

interface Table<R,C,V>

Коллекция, которая связывает упорядоченныйпара ключей, называемая ключом строки и ключом столбца, с одним значением.Таблица может быть разреженной, и только небольшая часть пар ключей строки / ключа столбца имеет соответствующее значение.

2 голосов
/ 16 июня 2011

Я бы порекомендовал перейти ко второму варианту

Map<Pair<K1,K2>,V>

Первый вызов вызовет больше перегрузки при извлечении данных и даже больше при вставке / удалении данных с карты.Каждый раз, когда вы вводите новое значение V, вам нужно проверить, существует ли карта для K1, если не создать ее, и поместить ее в основную карту, а затем поместить значение с помощью K2.

Есливы хотите иметь интерфейс, который вы выставляете изначально, оберните ваш Map<Pair<K1,K2>,V> своим собственным "DoubleKeyMap".

(И не забудьте правильно реализовать методы hash и equals в классе Pair !!)

1 голос
/ 16 июня 2011

Хотя я также согласен с тем, что вы предложили (пара значений для использования в качестве ключа), вы также можете рассмотреть возможность создания оболочки, которая может содержать / сочетать обе клавиши. Это может несколько запутать, поскольку вам нужно переопределить методы equals и hashCode и заставить это работать, но это может быть простой способ указать следующему человеку, использующему ваш код, что ключ должен быть специального типа.

Немного поиска, я нашел эту запись , которая может быть вам полезна. В частности, из коллекции Apache Commons, MultiKeyMap . Я никогда не использовал это раньше, но это выглядит как достойное решение и, возможно, стоит изучить.

1 голос
/ 16 июня 2011

Логически, ваша Пара (key1, key2) соответствует что-то , так как это ключ вашей карты.Поэтому вы можете написать свой собственный класс, имеющий K1 и K2 в качестве параметров, и переопределить метод hashCode () (плюс, возможно, другие методы для большего удобства).Очевидно, это «чистый» способ решения вашей проблемы.

1 голос
/ 16 июня 2011

Я бы выбрал решение Map<Pair<K1,K2>, V>, потому что:

  • это прямо выражает то, что вы хотите сделать
  • потенциально быстрее, потому что использует меньше косвенных указаний
  • упрощает код клиента (код, который использует Map впоследствии
0 голосов
/ 10 июля 2015

Я использовал массив для ключа: вот так

Map<Array[K1,K2], V>

...