Я ищу способ хранения пар ключ-значение. Мне нужно, чтобы поиск был двунаправленным, но в то же время мне нужно сохранить несколько значений для одного и того же ключа. Другими словами, что-то вроде BidiMap, но для каждого ключа может быть несколько значений. Например, он должен иметь возможность удерживать пары, такие как: "s1" → 1, "s2" → 1, "s3" → 2, и мне нужно получить значение, сопоставленное каждому ключу, и для каждого значения, получите все связанные с ним ключи.
Двунаправленная многозначная карта в Java
Ответ 1
Итак, вам нужна поддержка отношений "многие ко многим"? Ближе всего вы можете получить Guava Multimap
как @Mechkov написал, но более конкретно Multimap
комбинация с Multimaps.invertFrom
. "BiMultimap" еще не реализован, но есть проблема, запрашивающая эту функцию в библиотеке Google Guava.
На этом этапе у вас есть несколько вариантов:
-
Если ваш "BiMultimap" будет неизменным, используйте
Multimaps.invertFrom
иImmutableMultimap
/ImmutableListMultimap
/ImmutableSetMultimap
(каждый из этих трех имеет разные значения хранения коллекции). Некоторый код (пример, взятый из приложения I, используетEnum
иSets.immutableEnumSet
):public class RolesAndServicesMapping { private static final ImmutableMultimap<Service, Authority> SERVICES_TO_ROLES_MAPPING = ImmutableMultimap.<Service, Authority>builder() .put(Service.SFP1, Authority.ROLE_PREMIUM) .put(Service.SFP, Authority.ROLE_PREMIUM) .put(Service.SFE, Authority.ROLE_EXTRA) .put(Service.SF, Authority.ROLE_STANDARD) .put(Service.SK, Authority.ROLE_STANDARD) .put(Service.SFP1, Authority.ROLE_ADMIN) .put(Service.ADMIN, Authority.ROLE_ADMIN) .put(Service.NONE, Authority.ROLE_DENY) .build(); // Whole magic is here: private static final ImmutableMultimap<Authority, Service> ROLES_TO_SERVICES_MAPPING = SERVICES_TO_ROLES_MAPPING.inverse(); // before guava-11.0 it was: ImmutableMultimap.copyOf(Multimaps.invertFrom(SERVICES_TO_ROLES_MAPPING, HashMultimap.<Authority, Service>create())); public static ImmutableSet<Authority> getRoles(final Service service) { return Sets.immutableEnumSet(SERVICES_TO_ROLES_MAPPING.get(service)); } public static ImmutableSet<Service> getServices(final Authority role) { return Sets.immutableEnumSet(ROLES_TO_SERVICES_MAPPING.get(role)); } }
-
Если вы действительно хотите, чтобы ваш Multimap был модифицируемым, будет сложно поддерживать варианты K- > V и V- > K, если вы не будете изменять только
kToVMultimap
и вызыватьinvertFrom
каждый раз, когда вы хотите иметь свою инвертированную копию (и сделать эту копию немодифицируемой, чтобы убедиться, что вы случайно не изменяетеvToKMultimap
, что не будет обновлятьkToVMultimap
). Это не оптимально, но в этом случае должно быть сделано. -
(Не ваш случай, возможно, упоминается как бонус):
BiMap
интерфейс и классы реализации имеет метод.inverse()
, который даетBiMap<V, K>
вид изBiMap<K, V>
и сам послеbiMap.inverse().inverse()
. Если эта проблема, о которой я упоминал ранее, она, вероятно, будет иметь нечто похожее. -
(EDIT Октябрь 2016) Вы также можете использовать новый графический API, который будет присутствовать в Guava 20:
В целом, common.graph поддерживает графики следующих разновидностей:
- ориентированные графики
- неориентированные графики
- узлы и/или ребра со связанными значениями (веса, метки и т.д.)
- которые выполняют/не разрешают автопилы
- которые делают/не позволяют параллельные ребра (графики с параллельными ребрами иногда называют мультиграфами)
- чьи узлы/ребра упорядочиваются, сортируются или неупорядочены
Ответ 2
Что случилось с наличием двух карт, ключей- > значений, значений- > ключей?
Ответ 3
Я надеюсь, что использование MultivaluedMap решает проблему. Пожалуйста, найдите документацию от оракула ниже ссылки.
http://docs.oracle.com/javaee/6/api/javax/ws/rs/core/MultivaluedMap.html
Ответ 4
Используя Google Guava, мы можем написать примитивную BiMulitMap, как показано ниже.
import java.util.Collection;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
public class BiMultiMap<K,V> {
Multimap<K, V> keyToValue = ArrayListMultimap.create();
Multimap<V, K> valueToKey = ArrayListMultimap.create();
public void putForce(K key, V value) {
keyToValue.put(key, value);
valueToKey.put(value, key);
}
public void put(K key, V value) {
Collection<V> oldValue = keyToValue.get(key);
if ( oldValue.contains(value) == false ) {
keyToValue.put(key, value);
valueToKey.put(value, key);
}
}
public Collection<V> getValue(K key) {
return keyToValue.get(key);
}
public Collection<K> getKey(V value) {
return valueToKey.get(value);
}
@Override
public String toString() {
return "BiMultiMap [keyToValue=" + keyToValue + ", valueToKey=" + valueToKey + "]";
}
}
Надеемся, что это поможет некоторым элементарным потребностям Двунаправленной Мульти Карта. Обратите внимание, что K и V должны правильно реализовать метод hascode и equals
Ответ 5
Надеюсь, я понял тебя.
class A {
long id;
List<B> bs;
}
class B {
long id;
List<A> as;
}
Ответ 6
Реализация Google Guava MultiMap - это то, что я использую для этих целей.
Map<Key Collection<Values>>
где Collection может быть, например, ArrayList. Он позволяет сопоставить несколько значений, хранящихся в коллекции, с ключом. Надеюсь, это поможет!