Я ищу способ хранения пар ключ-значение. Мне нужно, чтобы поиск был двунаправленным, но в то же время мне нужно сохранить несколько значений для одного и того же ключа. Другими словами, что-то вроде 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. Он позволяет сопоставить несколько значений, хранящихся в коллекции, с ключом. Надеюсь, это поможет!