Как реализовать карту с несколькими ключами? [Дубликат]

143
задан nha 11 April 2016 в 15:48
поделиться

13 ответов

Две карты. Одна карта и одна карта . Если у вас должен быть один интерфейс, напишите класс-оболочку, который реализует указанные методы.

96
ответ дан 23 November 2019 в 22:54
поделиться

See Google Collections. Or, as you suggest, use a map internally, and have that map use a Pair. You'll have to write or find Pair<>; it's pretty easy but not part of the standard Collections.

0
ответ дан 23 November 2019 в 22:54
поделиться

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

0
ответ дан 23 November 2019 в 22:54
поделиться

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

0
ответ дан 23 November 2019 в 22:54
поделиться

Define a class that has an instance of K1 and K2. Then use that as class as your key type.

0
ответ дан 23 November 2019 в 22:54
поделиться

Звучит как кортеж Python. Следуя этому духу, вы можете создать собственный неизменный класс, который реализует Comparable, и вы его получите.

1
ответ дан 23 November 2019 в 22:54
поделиться

Я вижу следующие подходы:

a) Используйте 2 разные карты. Вы можете обернуть их в класс, как вы предлагаете, но даже это может быть излишним. Просто используйте карты непосредственно: Во многих общих случаях пробел key1 и пробел key2 не пересекаются. В этом случае вам не нужно делать ничего особенного. Просто определите карту, в которой есть записи key1 => v , а также key2 => v

2
ответ дан 23 November 2019 в 22:54
поделиться

Предложение, предложенное некоторыми ответчиками:

public interface IDualMap<K1, K2, V> {

    /**
    * @return Unmodifiable version of underlying map1
    */
    Map<K1, V> getMap1();

    /**
    * @return Unmodifiable version of underlying map2
    */
    Map<K2, V> getMap2();

    void put(K1 key1, K2 key2, V value);

}

public final class DualMap<K1, K2, V>
        implements IDualMap<K1, K2, V> {

    private final Map<K1, V> map1 = new HashMap<K1, V>();

    private final Map<K2, V> map2 = new HashMap<K2, V>();

    @Override
    public Map<K1, V> getMap1() {
        return Collections.unmodifiableMap(map1);
    }

    @Override
    public Map<K2, V> getMap2() {
        return Collections.unmodifiableMap(map2);
    }

    @Override
    public void put(K1 key1, K2 key2, V value) {
        map1.put(key1, value);
        map2.put(key2, value);
    }
}
5
ответ дан 23 November 2019 в 22:54
поделиться

Мне кажется, что методы, которые вы хотите задать в своем вопросе, поддерживаются непосредственно Map. Кажется, вам нужны

put(K1 key, K2 key, V value)
put(K1 key, V value)
put(K2 key, V value)

. Обратите внимание, что в map, get () и containsKey () и т. Д. Все принимают Object аргументы. , Ничто не мешает вам использовать один метод get () для делегирования всем составным картам, которые вы объединяете (как указано в вашем вопросе и других ответах). Возможно, вам понадобится регистрация типа, чтобы не возникло проблем с приведением классов (если они специальные + наивно реализованы.

Типизированная регистрация также позволит вам получить "правильную" карту, которая будет использоваться:

Map<T,V> getMapForKey(Class<T> keyClass){
  //Completely naive implementation - you actually need to 
  //iterate through the keys of the maps, and see if the keyClass argument
  //is a sub-class of the defined map type.  And then ordering matters with 
  //classes that implement multiple interfaces...
  Map<T,V> specificTypeMap = (Map<T,V) maps.get(keyClass);
  if (specificTypeMap == null){
     throw new IllegalArgumentException("There is no map keyed by class" + keyClass);
  }
  return maps.get(keyClass);
}

V put(Object key, V value) {
  //This bit requires generic suppression magic - but 
  //nothing leaves this class and you're testing it right? 
  //(You can assert that it *is* type-safe)
  Map map = getMapForKey(key.getClass());
  map.put(object, key);
}

void put(Object[] keys, V value) { //Or put(V value, Object ... keys)
   //Might want to catch exceptions for unsupported keys and log instead?
   .....
}

] Просто идеи ...

0
ответ дан 23 November 2019 в 22:54
поделиться

Я все еще собираюсь предложить решение с двумя картами, но с помощью твиста

Map<K2, K1> m2;
Map<K1, V>  m1;

Эта схема позволяет вам иметь произвольное количество ключевых «псевдонимов».

Она также позволяет вам обновлять значение через любой ключ без рассинхронизации карт.

40
ответ дан 23 November 2019 в 22:54
поделиться

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

0
ответ дан 23 November 2019 в 22:54
поделиться

Commons-collections предоставляет именно то, что вы ищете: https://commons.apache.org/proper/commons-collections/apidocs/

Похоже, сейчас общие коллекции напечатаны.

Типизированную версию можно найти по адресу: https://github.com/megamattron/collections-generic

Это точно соответствует вашему варианту использования:

 MultiKeyMap<k1,k2,...,kn,v> multiMap = ??
47
ответ дан 23 November 2019 в 22:54
поделиться

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

Иногда дженерики просто не стоят дополнительной работы.

4
ответ дан 23 November 2019 в 22:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: