2009-08-06 7 views
9

Lo que necesito es una colección que permita que varias claves accedan a un solo objeto.Necesita una tabla/mapa Java con varias claves para un valor. El valor se altera comúnmente

Necesito aplicar alteraciones frecuentes a este objeto.

También debe ser eficiente para entradas de 500k +.

+0

¿Ha invertido su pregunta por accidente? Porque dice "... Map permite que una tecla acceda a múltiples valores", lo que no es cierto para la interfaz de Map. Es un mapeo uno a uno entre la clave y el valor (aunque, por supuesto, tu valor puede ser una colección) – Falaina

+0

Cuando dices * "alteraciones frecuentes en este objeto" * ¿a qué te refieres exactamente? ¿Quiere decir que el objeto es mutable y cambia su estado? ¿O quiere decir que necesita reemplazar un mapeo por otro (y reemplazarlo por cada clave asociada)? –

Respuesta

15

Cualquier implementación de java.util.Map<K,V> va a hacer esto - no es ninguna restricción de la cantidad de veces que un valor particular, se puede añadir en las teclas separadas:

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

Si desea un mapa donde se asocia una sola tecla con varios valores, esto se llama una multi-mapa y se puede obtener uno de la google java collections API o desde Apache's commons-collections

+3

el problema con este enfoque es que no puede eliminar rápidamente el objeto de todas las claves asociadas con él – njzk2

+0

@ njzk2 que no es necesariamente un requisito. "Debe ser eficiente para 500k + entradas" es muy vago. –

3

Uhm ...

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

Ahora el mapa contiene el mismo valor dos veces, accesible a través de diferentes teclas. Si eso no es lo que estás buscando, debes volver a trabajar tu pregunta. :)

2

este puede hacer lo que quiera:

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

Totalmente respondí una pregunta similar que tuve. – elToro

3

en cierto modo me interpretó su solicitud de manera diferente. ¿Qué ocurre si uno quiere dos juegos de claves completamente diferentes para acceder a los mismos valores subyacentes? Por ejemplo:

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

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

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

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

Obviamente tener dos mapas, uno para las teclas de números enteros y uno para las claves de cadena, no se va a trabajar, ya que una actualización en un mapa no se reflejará en el otro mapa. Supongamos que ha modificado el Map<String,Object>, actualizando "Monkey" para asignar a fifthObject. El resultado de esta modificación es cambiar el Entry<String,Object> dentro de ese mapa, pero esto, por supuesto, no tiene ningún efecto en el otro mapa. Así, pese a lo que pretendía era:

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

lo que te dan en la realidad sería la siguiente:

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

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

lo que hago en esta situación es que el dos de lado a lado mapas, pero en su lugar de hacerles decir Map<String, Integer> Los haría Map<String, Integer[]>, donde la matriz asociada es una matriz de un solo miembro. La primera vez que asocie una clave con un valor, si aún no existe una matriz y la tecla devuelve nulo, creo la matriz y asocio con ella cualquier otra clave que desee (en el mapa de esa tecla). Posteriormente, solo modifico el contenido de la matriz, pero nunca la referencia a la matriz en sí misma, y ​​esto funciona con encanto.

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

Y tampoco tiene que haber dos clases diferentes que comprendan los conjuntos de teclas: ambas podrían ser cadenas, por ejemplo – fragorl

0

Su pregunta realmente me hizo pensar en hacer esta clase para manejar tal cosa. Actualmente estoy trabajando en un motor de juego en 2D y tu pregunta me hizo pensar en todo lo que necesitaba.

Por cierto, lo has redactado, creo que lo que quieres es;

Objeto que contiene claves y valores, pero también puede mantener los valores de las teclas comunes en espera (utilizo este objeto específicamente para reducir la CPU a costa de usar solo un poco más de memoria.)

This Class 'El tipo K es el tipo de clave primaria. El tipo T es el tipo de valor HashSet.

La forma de implementar y utilizar este objeto es:

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

Usted tendrá que mantener las etiquetas únicas en un conjunto o ArrayList en cualquier clase que implemente esto, porque si no lo hiciste estarías almacenando entidades y no sabrías cuál fue cuál. Así que guarde el entero que obtiene del método put() en un arraylist o conjunto, y repítalo.

Puede verificar los valores de esta Clase si existen, o en qué objetos clave está establecido el valor.

Aquí está el Class 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;    
     } 


} 
Cuestiones relacionadas