2009-08-06 6 views
9

Ciò di cui ho bisogno è una raccolta che consente a più chiavi di accedere a un singolo oggetto.È necessaria una mappa/tabella Java con più chiavi per un valore. Il valore è comunemente modificato

Ho bisogno di applicare frequenti modifiche a questo oggetto.

Inoltre, deve essere efficiente per le voci 500k +.

+0

Hai invertito la domanda per sbaglio? Perché si afferma "... Mappa consente a una chiave di accedere a più valori", che non è vero per l'interfaccia della mappa. È una mappatura uno a uno tra la chiave e il valore (anche se, naturalmente, il tuo valore può essere una collezione) – Falaina

+0

Quando dici * "frequenti alterazioni a questo oggetto" * cosa intendi esattamente? Intendi dire che l'oggetto è mutabile e cambi il suo stato? O vuoi dire che devi sostituire una mappatura con un'altra (e sostituirla per ogni chiave associata)? –

risposta

15

Qualsiasi implementazione di java.util.Map<K,V> farà questo - non v'è alcuna restrizione su quante volte un particolare valore può essere aggiunto sotto tasti separati:

Map<String,Integer> m = new HashMap<String, Integer>(); 
m.put("Hello", 5); 
m.put("World", 5); 
System.out.println(m); // { Hello->5, World->5 } 

Se si desidera una mappa in cui è associato un singolo tasto con più valori, questo si chiama un multi-mappae si può ottenere uno dal google java collections API o da Apache's commons-collections

+3

il problema con questo approccio è che non è possibile rimuovere rapidamente l'oggetto da tutte le chiavi ad esso associate – njzk2

+0

@ njzk2 che non è necessariamente un requisito. "Deve essere efficiente per le voci di 500k +" è molto vago. –

3

Uhm ...

Map map = new HashMap(); 
Object someValue = new Object(); 
map.put(new Object(), someValue); 
map.put(new Object(), someValue); 

Ora la mappa contiene lo stesso valore due volte, accessibile tramite chiavi diverse. Se non è quello che stai cercando, dovresti rielaborare la tua domanda. :)

2

questo può fare quello che vuoi:

import java.util.*; 
class Value { 
    public String toString() { 
     return x.toString(); 
    } 
    Integer x=0; 
} 
public class Main { 
    public static void main(String[] arguments) { 
     Map m=new HashMap(); 
     final Value v=new Value(); 
     m.put(1,v); 
     m.put(2,v); 
     System.out.println(m.get(1)); 
     System.out.println(m.get(2)); 
     v.x=42; 
     System.out.println(m.get(1)); 
     System.out.println(m.get(2)); 
    } 
+0

Completamente risposto a una domanda simile che ho avuto. – elToro

3

I sorta di interpretavo la sua richiesta in modo diverso. Cosa succede se si vogliono due keysets completamente diversi per accedere agli stessi valori sottostanti. Ad esempio:

"Hello" ------| 
        |----> firstObject 
     3  ------| 

    "Monkey" ------| 
        |----> secondObject 
     72  ------| 

     14  -----------> thirdObject 

    "Baseball" ------| 
        |----> fourthObject 
     18  ------| 

Ovviamente avere due mappe, una per le chiavi intere e uno per le chiavi stringa, non è andare a lavorare, poiché un aggiornamento in una mappa non rifletterà nella altra mappa. Supponendo di aver modificato Map<String,Object>, l'aggiornamento di "Monkey" per eseguire il mapping su fifthObject. Il risultato di questa modifica è di cambiare il Entry<String,Object> all'interno di quella mappa, ma questo naturalmente non ha alcun effetto sull'altra mappa. Così, mentre quello che intendeva era:

"Monkey" ------| 
        |----> fifthObject 
     72  ------| 

quello che si otterrebbe in realtà sarebbe questo:

"Monkey" -----------> fifthObject 

     72  -----------> secondObject 

quello che faccio in questa situazione è quello di avere i due fianco a mappe laterali, ma invece di farli dire Map<String, Integer> li farei Map<String, Integer[]>, dove l'array associato è un array a membro singolo. La prima volta che associo una chiave a un valore, se non esiste ancora alcuna matrice e la chiave restituisce null, creo la matrice e associo qualsiasi altra chiave che desidero con essa (nella mappa di quella chiave). Successivamente, modifico solo i contenuti dell'array, ma mai il riferimento alla matrice stessa, e questo ha un fascino.

"Monkey" -------> fifthObjectArray ------| 
               |-----> fifthObjectArray[0] 
     72  -------> fifthObjectArray ------| 
+0

E non devono essere due classi diverse che comprendono i keysets - potrebbero essere entrambe le stringhe, per esempio – fragorl

0

La tua domanda mi ha fatto davvero pensare di fare in modo che questa classe gestisse una cosa del genere. Attualmente sto lavorando a un motore di gioco 2D e la tua domanda mi ha fatto pensare esattamente a ciò di cui avevo bisogno.

A proposito, lo credo, quello che vuoi è;

Un oggetto che contiene chiavi e valori, ma è anche possibile mantenere i valori delle chiavi comuni (uso questo oggetto specificamente per ridurre la CPU al costo di utilizzare solo un po 'di memoria in più.)

Questa classe 'Il tipo K è il tipo di chiave primaria. Il tipo T è il tipo di valore HashSet.

Il modo in cui si sceglie di implementare e utilizzare questo oggetto è:

MapValueSet<ObjectType1,ObjectType2> mainmap = new 

MapValueSet<ObjectType1,ObjectType2>() 
HashSet<Integer> tags = new HashSet<Integer>(); 
     public void test(){ 
      ObjectType1 = new ObjectType1(); 
      ObjectType2 = new ObjectType2(); 

      tags.add(mainmap.put(ObjectType1,ObjectType2); 
      mainmap.get(ObjectType1,Integer); 
     } 

Avrete bisogno di tenere i tag univoci in un set o ArrayList in qualsiasi classe di implementare questo perché se si didn Saresti conservando le entità e non sapendo quale fosse. Quindi memorizza il numero intero che ottieni dal metodo put() in un array o un set, e itera attraverso quello.

È possibile controllare i valori di questa classe, se esistono, o quali oggetti chiave il valore è impostato su.

Ecco la classe MapValueSet;

import java.util.HashMap; 
import java.util.HashSet; 
import java.util.Map; 

public class MapValueSet<K,T> { 

     Indexer indxK = new Indexer(); 
     Indexer indxT = new Indexer(); 

     Map<K,Integer> kTags = new HashMap<K,Integer>(); 
     Map<T,Integer> tTags = new HashMap<T,Integer>(); 

     Map<Integer,HashSet<Integer>> MapK = new HashMap<Integer,HashSet<Integer>>(); 

     Map<Integer,HashSet<Integer>> MapT = new HashMap<Integer,HashSet<Integer>>(); 

public int put(K k, T t){ 
    int tag = -1; 
    if(!kTags.containsKey(k)){ 
     kTags.put(k, indxK.getNextTag()); 
    } 

    if(!MapK.containsKey(kTags.get(k))){ 
     MapK.put(kTags.get(k), new HashSet<Integer>()); 
    } 

    if(!tTags.containsKey(t)){ 
     tTags.put(t, tag = indxT.getNextTag()); 
    } 

    if(!MapT.containsKey(tTags.get(t))){ 
     MapT.put(tag = tTags.get(t), new HashSet<Integer>()); 
    }  
     MapK.get(kTags.get(k)).add(tTags.get(t)); 
     MapT.get(tag = tTags.get(t)).add(kTags.get(k)); 

    return tag; 
} 

     @SuppressWarnings("unchecked") 
     public T get(K k, int tag){ 
      Object[] tArr = tTags.keySet().toArray(); 
      for(int i = 0; i < tArr.length; i++){ 
       if(tTags.get((T)tArr[i])== tag){ 
        return (T)tArr[i]; 
      } 
      } 
      return null; 
     } 

     public boolean removeAtKey(K k, T t){ 
       int kTag = -1; 
       int tTag = -1; 

       if(kTags.get(k) != null){ 
       kTag = kTags.get(k); 
       } 

       if(tTags.get(t) != null){ 
       tTag = tTags.get(t); 
       } 

       if(kTag == -1 || tTag == -1){ 
         System.out.println("Keys are Blank at: removeAtKey(k,t)"); 
         return false; 
       } 

       boolean removed = false; 

         if(MapK.get(kTag) != null){ 
           removed = MapK.get(kTag).remove(tTag); 
         } 
         if(MapT.get(tTag) != null){ 
           MapT.get(tTag).remove(kTag); 
         } 

         if(!MapK.containsKey(kTag)){ 
           kTags.remove(k); 
           indxK.removeTag(kTag); 
         } 

         if(MapK.containsKey(kTag)){ 
           tTags.remove(t); 
           indxT.removeTag(tTag); 

         } 

       return removed; 
     } 

     public void removeAtValue(T t){ 
       if(!tTags.containsKey(t)){ 
         return; 
       } 
       Object[] keyArr = MapT.get(tTags.get(t)).toArray(); 

       for(int i = 0; i < keyArr.length; i++){ 
         MapK.get(keyArr[i]).remove(tTags.get(t)); 
       } 

         indxT.removeTag(tTags.get(t)); 
         MapT.remove(tTags.get(t)); 
         tTags.remove(t); 
     } 

     public boolean mapContains(T t){ 
       if(tTags.get(t) == null){ 
         return false; 
       } 
       int tTag = tTags.get(t); 

       return MapT.get(tTag) != null && !MapT.get(tTag).isEmpty(); 
     } 

     public boolean containsKey(K k){ 

       if(kTags.get(k) == null){ 
         return false; 
       } 

       return MapK.containsKey(kTags.get(k)); 
     } 

     public boolean keyContains(K k, T t){ 

       if(kTags.get(k) != null && tTags.get(t) != null){ 
         return MapK.get(kTags.get(k)).contains(tTags.get(t)); 
       } 

       return false; 

     } 

     @Override 
     public String toString(){ 

       String s = ""; 

       s = s+ "Key  Map: " + MapK.toString() + "\n"; 
       s = s+ "Value Map: " + MapT.toString() + "\n"; 
       s = s+ "KeyTag Map: " + kTags.toString() + "\n"; 
       s = s+ "ValueTag Map: " + tTags.toString() + "\n"; 
       s = s+ "KeyTag List: " + indxK.activeSet().toString() + "\n"; 
       s = s+ "ValueTag List: " + indxT.activeSet().toString(); 

       return s;    
     } 


} 
Problemi correlati