Mappa multivalore bidirezionale in Java

Sto cercando un modo per memorizzare coppie chiave-valore. Ho bisogno che la ricerca sia bidirezionale, ma allo stesso tempo ho bisogno di memorizzare più valori per la stessa chiave. In altre parole, qualcosa come una BidiMap, ma per ogni chiave ci possono essere più valori. Ad esempio, deve essere in grado di contenere coppie come: “s1” -> 1, “s2” -> 1, “s3” -> 2, e ho bisogno di essere in grado di ottenere il valore mappato a ciascuna chiave, e per ogni valore, prendi tutte le chiavi ad esso associate.

Quindi hai bisogno di supporto per le relazioni molti-a-molti? Il più vicino si può ottenere è la Multimap Guava come ha scritto @Mechkov – ma più specificamente la combinazione Multimaps.invertFrom con Multimaps.invertFrom . “BiMultimap” non è ancora implementato, ma c’è un problema che richiede questa funzione nella libreria Google Guava.

A questo punto hai poche opzioni:

  1. Se il tuo “BiMultimap” sta per costante immutabile – usa Multimaps.invertFrom e ImmutableMultimap / ImmutableListMultimap / ImmutableSetMultimap (ognuno di questi tre ha diversi valori di memorizzazione delle collezioni). Qualche codice (esempio tratto dall’app che sviluppo, utilizza Enum s e 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. Se vuoi veramente che il tuo Multimap sia modificabile, sarà difficile mantenere entrambe le varianti K-> V e V-> K a meno che tu non modifichi solo kToVMultimap e chiami invertFrom ogni volta che vuoi avere la sua copia invertita (e facendo ciò copia immodificabile per essere sicuro di non modificare accidentalmente vToKMultimap cosa non aggiornerebbe kToVMultimap ). Questo non è ottimale, ma dovrebbe essere fatto in questo caso.

  3. (Probabilmente il tuo caso non è menzionato come bonus): BiMap interfaccia BiMap e le classi di implementazione hanno il metodo .inverse() che fornisce la BiMap di BiMap da BiMap e stessa dopo biMap.inverse().inverse() . Se il problema che ho menzionato prima è già fatto, probabilmente avrà qualcosa di simile.

  4. (EDIT Ottobre 2016) Puoi anche utilizzare la nuova API grafico che sarà presente in Guava 20 :

    Nel complesso, common.graph supporta grafici delle seguenti varietà:

    • grafici diretti
    • grafici non orientati
    • nodes e / o spigoli con valori associati (pesi, etichette, ecc.)
    • grafici che non consentono i self-loop
    • grafici che non consentono i bordi paralleli (i grafici con bordi paralleli sono talvolta chiamati multigrafi)
    • grafici i cui nodes / bordi sono ordinati per l’inserimento, ordinati o non ordinati

Cosa c’è di sbagliato nell’avere due mappe, chiave-> valori, valori-> chiavi?

Spero che l’uso di MultivaluedMap risolva il problema. Si prega di trovare la documentazione da oracle sotto il collegamento.

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

Usando Google Guava possiamo scrivere una primitiva BiMulitMap come di seguito.

 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 + "]"; } } 

Spero che questo aiuti alcune necessità di base della Multi mappa bidirezionale. Nota che K e V devono implementare correttamente il metodo hascode e equals

Spero di averti capito bene

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

L’implementazione di Google Guava MultiMap è ciò che sto usando per questi scopi.

 Map> 

dove Collection può essere un ArrayList ad esempio. Consente a più valori memorizzati in una raccolta di essere mappati su una chiave. Spero che questo ti aiuti!