Mapa bidireccional de valores múltiples en Java

Estoy buscando una manera de almacenar pares clave-valor. Necesito que la búsqueda sea bidireccional, pero al mismo tiempo necesito almacenar valores múltiples para la misma clave. En otras palabras, algo así como BidiMap, pero para cada clave puede haber múltiples valores. Por ejemplo, debe ser capaz de mantener pares como: “s1” -> 1, “s2” -> 1, “s3” -> 2, y necesito poder asignar el valor asignado a cada tecla, y para cada valor, obtenga todas las claves asociadas con él.

¿Entonces necesitas soporte para relaciones de muchos a muchos? Lo más cerca que puedes conseguir es Guava ‘s Multimap como escribió @Mechkov, pero más específicamente combinación de Multimaps.invertFrom con Multimaps.invertFrom . “BiMultimap” aún no está implementado, pero hay un problema al solicitar esta función en la biblioteca de Google Guava.

En este punto tienes pocas opciones:

  1. Si su “BiMultimap” va a ser constante inmutable, use Multimaps.invertFrom e ImmutableMultimap / ImmutableListMultimap / ImmutableSetMultimap (cada uno de estos tres tiene diferentes valores de almacenamiento de recostackción). Cierto código (ejemplo tomado de la aplicación que desarrollo, utiliza Enum s y Sets.immutableEnumSet ):

     public class RolesAndServicesMapping { private static final ImmutableMultimap SERVICES_TO_ROLES_MAPPING = ImmutableMultimap.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 ROLES_TO_SERVICES_MAPPING = SERVICES_TO_ROLES_MAPPING.inverse(); // before guava-11.0 it was: ImmutableMultimap.copyOf(Multimaps.invertFrom(SERVICES_TO_ROLES_MAPPING, HashMultimap.create())); public static ImmutableSet getRoles(final Service service) { return Sets.immutableEnumSet(SERVICES_TO_ROLES_MAPPING.get(service)); } public static ImmutableSet getServices(final Authority role) { return Sets.immutableEnumSet(ROLES_TO_SERVICES_MAPPING.get(role)); } } 
  2. Si realmente quieres que tu Multimap sea modificable, será difícil mantener las variantes K-> V y V-> K a menos que solo modifiques kToVMultimap y llames a invertFrom cada vez que quieras tener su copia invertida (y hacer eso copia no modificable para asegurarte de que accidentalmente no modifique vToKMultimap lo que no actualizaría kToVMultimap ). Esto no es óptimo, pero debería hacerlo en este caso.

  3. (Probablemente no sea tu caso, mencionado como bonificación): la interfaz BiMap y la implementación de clases tiene el método .inverse() que da a BiMap vista de BiMap y de sí mismo después de biMap.inverse().inverse() . Si este problema que mencioné antes está hecho, probablemente tendrá algo similar.

  4. (EDITAR en octubre de 2016) También puede usar la nueva API gráfica que estará presente en Guava 20 :

    En general, common.graph admite gráficos de las siguientes variedades:

    • gráficos dirigidos
    • gráficos no dirigidos
    • nodos y / o bordes con valores asociados (pesos, tags, etc.)
    • gráficos que sí / no permiten bucles automáticos
    • gráficos que sí / no permiten bordes paralelos (los gráficos con bordes paralelos a veces se llaman multigrafos)
    • gráficos cuyos nodos / bordes están ordenados por inserción, ordenados o desordenados

¿Qué hay de malo en tener dos mapas, clave-> valores, valores-> claves?

Espero que el uso de MultivaluedMap resuelva el problema. Encuentre la documentación de Oracle a continuación del enlace.

http://docs.oracle.com/javaee/6/api/javax/ws/rs/core/MultivaluedMap.html

Usando Google Guava podemos escribir un BiMulitMap primitivo como se muestra a continuación.

 import java.util.Collection; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; public class BiMultiMap { Multimap keyToValue = ArrayListMultimap.create(); Multimap 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 oldValue = keyToValue.get(key); if ( oldValue.contains(value) == false ) { keyToValue.put(key, value); valueToKey.put(value, key); } } public Collection getValue(K key) { return keyToValue.get(key); } public Collection getKey(V value) { return valueToKey.get(value); } @Override public String toString() { return "BiMultiMap [keyToValue=" + keyToValue + ", valueToKey=" + valueToKey + "]"; } } 

Espero que esto ayude a algunas necesidades básicas del Mapa múltiple bi-direccional. Tenga en cuenta que K y V deben implementar el método hascode y equals correctamente

Espero haberte hecho bien

 class A { long id; List bs; } class B { long id; List as; } 

La implementación de Google Guava MultiMap es lo que estoy usando para estos propósitos.

 Map> 

donde Collection puede ser una ArrayList, por ejemplo. Permite mapear múltiples valores almacenados en una colección a una clave. ¡Espero que esto ayude!