2009-08-06 11 views
9

Potrzebuję kolekcji, która pozwala wielu kluczom uzyskać dostęp do pojedynczego obiektu.Potrzebujesz mapy/tabeli Java z wieloma kluczami do jednej wartości. Wartość jest często zmieniana.

Potrzebuję zastosować częste zmiany do tego obiektu.

Musi być także skuteczny przy wpisach 500k +.

+0

Czy cofnąłeś pytanie przez przypadek? Ponieważ podajesz "... Mapa pozwala na jeden klucz, aby uzyskać dostęp do wielu wartości", co nie jest prawdą w interfejsie Map. To odwzorowanie "jeden do jednego" pomiędzy kluczem a wartością (choć oczywiście twoja wartość może być zbiorem) – Falaina

+0

Kiedy mówisz "częste zmiany tego obiektu" * co masz na myśli? Czy masz na myśli, że obiekt jest zmienny i zmieniasz jego stan? Czy masz na myśli, że musisz zamienić jedno mapowanie na inne (i zastąpić je dla każdego przypisanego klucza)? –

Odpowiedz

15

Każda realizacja java.util.Map<K,V> będzie to zrobić - nie ma żadnych ograniczeń na to, ile razy dana wartość może być dodany na podstawie odrębnych klawiszy:

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

Jeśli chcesz mapę gdzie pojedynczy klucz jest skojarzony z wielu wartości, nazywa się to multi-mapa i można dostać jedną z google java collections API lub z Apache's commons-collections

+3

Problem z tym podejściem polega na tym, że nie można szybko usunąć obiektu ze wszystkich kluczy związanych z nim – njzk2

+0

@ njzk2, który niekoniecznie jest wymagany. "Musi być sprawne dla 500k wpisów" jest bardzo niejasne. –

3

uhm ...

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

Teraz mapa zawiera tę samą wartość dwukrotnie, dostępną za pośrednictwem różnych klawiszy. Jeśli nie tego szukasz, powinieneś przerobić swoje pytanie. :)

2

to może rób co chcesz:

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

Całkowicie odpowiedział na podobne pytanie, które miałem. – elToro

3

ja rodzaj interpretować jego prośbę inaczej. Co jeśli chcemy dwa kompletnie różne zestawy kluczy, aby uzyskać dostęp do tych samych podstawowych wartości. Na przykład:

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

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

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

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

Oczywiście mając dwie mapy, jedna dla klawiszy całkowitych i jeden dla kluczy ciąg, nie będzie działać, ponieważ aktualizacja w jednej mapie nie odzwierciedlają w drugiej mapie. Przypuśćmy, że zmodyfikowałeś Map<String,Object>, aktualizując "Małpę", aby odwzorować do piątego obiektu. Wynikiem tej modyfikacji jest zmiana Entry<String,Object> w obrębie tej mapy, ale to oczywiście nie ma wpływu na drugą mapę. Dlatego, choć to, co było przeznaczone:

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

, co można dostać w rzeczywistości byłoby to:

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

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

co zrobić w tej sytuacji jest to, aby mieć dwóch sąsiadujących ze sobą mapy ubocznych, ale zamiast sprawiają, że mówią: Map<String, Integer> Zrobiłbym je Map<String, Integer[]>, gdzie powiązana tablica jest tablicą z jednym elementem. Za pierwszym razem, gdy klucz jest powiązany z wartością, jeśli nie istnieje jeszcze tablica, a klucz zwraca wartość null, tworzę tablicę i kojarzę z nią dowolny inny klucz (na mapie tego klucza). Później modyfikuję tylko zawartość tablicy, ale nigdy nie odwołuję się do samej tablicy, a to działa na urok.

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

I nie muszą to być dwie różne klasy, które zawierają zestawy kluczy - mogą to być oba łańcuchy, na przykład – fragorl

0

Twoje pytanie naprawdę sprawiło, że pomyślałem o tym, aby ta klasa poradziła sobie z taką sprawą. Obecnie pracuję nad silnikiem gry 2D, a twoje pytanie całkowicie mnie zastanowiło, czego potrzebuję.

Przy okazji, jak to sformułowałeś, wierzę w to, czego chcesz;

Obiekt przechowujący klucze i wartości, ale można również uzyskać wartości wspólnych kluczy (używam tego obiektu do wycinania procesora, kosztem nieco więcej pamięci.)

Ta klasa "Typ K jest rodzajem klucza podstawowego. Typ T to typ wartości HashSet.

Sposób wdrażania i korzystania z tego obiektu jest:

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); 
     } 

Musisz posiadać unikalne znaczniki w zestawie lub ArrayList w dowolnej klasy zaimplementować to, ponieważ jeśli nie zrobił nie przechowujesz bytów i nie wiesz, który z nich był. Więc przechowuj liczbę całkowitą, którą dostajesz z metody put() do tablicy lub zestawu, i iteruj przez nią.

Możesz sprawdzić wartości tej klasy, jeśli istnieją, lub które kluczowe obiekty mają tę wartość.

Oto klasa 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;    
     } 


} 
Powiązane problemy