Pregunta

Quiero tener un mapa con claves duplicadas.

Sé que hay muchas implementaciones de mapa (Eclipse me muestra alrededor de 50), por lo que apuesto a que debe haber uno que permite esto. Sé que es fácil de escribir su propio mapa que hace esto, pero yo prefiero utilizar alguna solución existente.

Tal vez algo en Commons-colecciones o Google-colecciones?

¿Fue útil?

Solución

Usted está buscando un multimap, y de hecho ambos Commons-colecciones y guayaba tiene varias implementaciones para eso. Multimapas permiten múltiples teclas mediante el mantenimiento de una colección de valores por clave, es decir, se puede poner un solo objeto en el mapa, pero puede recuperar una colección.

Si puede utilizar Java 5, preferiría Guava Multimap ya que es genéricos para notificaciones.

Otros consejos

No necesitamos depender de biblioteca externa de Google Colecciones. Simplemente puede aplicar el siguiente mapa:

Map<String, ArrayList<String>> hashMap = new HashMap<String, ArrayList>();

public static void main(String... arg) {
   // Add data with duplicate keys
   addValues("A", "a1");
   addValues("A", "a2");
   addValues("B", "b");
   // View data.
   Iterator it = hashMap.keySet().iterator();
   ArrayList tempList = null;

   while (it.hasNext()) {
      String key = it.next().toString();             
      tempList = hashMap.get(key);
      if (tempList != null) {
         for (String value: tempList) {
            System.out.println("Key : "+key+ " , Value : "+value);
         }
      }
   }
}

private void addValues(String key, String value) {
   ArrayList tempList = null;
   if (hashMap.containsKey(key)) {
      tempList = hashMap.get(key);
      if(tempList == null)
         tempList = new ArrayList();
      tempList.add(value);  
   } else {
      tempList = new ArrayList();
      tempList.add(value);               
   }
   hashMap.put(key,tempList);
}

Por favor, asegúrese de ajustar el código.

Multimap<Integer, String> multimap = ArrayListMultimap.create();

multimap.put(1, "A");
multimap.put(1, "B");
multimap.put(1, "C");
multimap.put(1, "A");

multimap.put(2, "A");
multimap.put(2, "B");
multimap.put(2, "C");

multimap.put(3, "A");

System.out.println(multimap.get(1));
System.out.println(multimap.get(2));       
System.out.println(multimap.get(3));

La salida es:

[A,B,C,A]
[A,B,C]
[A]

Nota: tenemos que importar archivos de la biblioteca

.

http://www.java2s.com/Code/Jar/g/ Downloadgooglecollectionsjar.htm

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

o https://commons.apache.org/proper/commons-collections /download_collections.cgi

import org.apache.commons.collections.MultiMap;
import org.apache.commons.collections.map.MultiValueMap;

Usted podría simplemente pasa una matriz de valores para el valor en un HashMap regular, simulando así duplicados de las llaves, y sería hasta usted para decidir qué datos desea utilizar.

Es posible que también acaba de utilizar un MultiMap , aunque no me gusta la idea de duplicados de las llaves a mí mismo.

Si desea iterar sobre una lista de pares de valores-clave (como los escribió en el comentario), a continuación, una lista o una matriz debería ser mejor. En primer lugar combinar sus claves y valores:

public class Pair
{
   public Class1 key;
   public Class2 value;

   public Pair(Class1 key, Class2 value)
   {
      this.key = key;
      this.value = value;
   }

}

Reemplazar Clase 1 y Clase 2 con los tipos que desea utilizar para las claves y valores.

Ahora usted puede ponerlos en una matriz o una lista e iterar sobre ellos:

Pair[] pairs = new Pair[10];
...
for (Pair pair : pairs)
{
   ...
}
commons.apache.org

MultiValueMap class

Este problema se puede resolver con una lista de List<Map.Entry<K,V>> mapa de entradas. No necesitamos usar ni bibliotecas externas ni nueva aplicación de Mapa. Una entrada de mapa se puede crear de esta manera:     Map.Entry<String, Integer> entry = new AbstractMap.SimpleEntry<String, Integer>("key", 1);

Aprender de mis errores ... por favor no aplicar esto por su cuenta. multimap guayaba es el camino a seguir.

Una mejora común requerida en Multimapas es no permitir pares duplicados teclas de valor.

La implementación / cambiar esto en un su aplicación puede ser molesto.

En la guayaba su tan simple como:

HashMultimap<String, Integer> no_dupe_key_plus_val = HashMultimap.create();

ArrayListMultimap<String, Integer> allow_dupe_key_plus_val = ArrayListMultimap.create();

Yo tenía una variante ligeramente diferente de este tema: Fue necesario asociar dos valores diferentes con la misma clave. La simple publicación de aquí en caso de que ayuda a los demás, he introducido un HashMap como el valor:

/* @param frameTypeHash: Key -> Integer (frameID), Value -> HashMap (innerMap)
   @param innerMap: Key -> String (extIP), Value -> String
   If the key exists, retrieve the stored HashMap innerMap 
   and put the constructed key, value pair
*/
  if (frameTypeHash.containsKey(frameID)){
            //Key exists, add the key/value to innerHashMap
            HashMap innerMap = (HashMap)frameTypeHash.get(frameID);
            innerMap.put(extIP, connName+":"+frameType+":"+interfaceName);

        } else {
            HashMap<String, String> innerMap = new HashMap<String, String>();
            innerMap.put(extIP, connName+":"+frameType+":"+interfaceName);
            // This means the key doesn't exists, adding it for the first time
            frameTypeHash.put(frameID, innerMap );
        }
}

En el código anterior el frameID clave se lee de primera cadena de un archivo de entrada en cada línea, el valor para frameTypeHash se construye mediante la división de la línea restante y se almacena como objeto String originalmente, durante un período de tiempo que el archivo comenzó a tener múltiples líneas (con diferentes valores) asociado con misma clave frameID, por lo frameTypeHash se sobrescribe con última línea como el valor. Substituí el objeto String con otro objeto HashMap como el campo de valor, esto ayudó en el mantenimiento de una sola tecla a diferente asignación de valores.

class  DuplicateMap<K, V> 
{
    enum MapType
    {
        Hash,LinkedHash
    }

    int HashCode = 0;
    Map<Key<K>,V> map = null;

    DuplicateMap()
    {
        map = new HashMap<Key<K>,V>();
    }

    DuplicateMap( MapType maptype )
    {
        if ( maptype == MapType.Hash ) {
            map = new HashMap<Key<K>,V>();
        }
        else if ( maptype == MapType.LinkedHash ) {
            map = new LinkedHashMap<Key<K>,V>();
        }
        else
            map = new HashMap<Key<K>,V>();
    }

    V put( K key, V value  )
    {

        return map.put( new Key<K>( key , HashCode++ ), value );
    }

    void putAll( Map<K, V> map1 )
    {
        Map<Key<K>,V> map2 = new LinkedHashMap<Key<K>,V>();

        for ( Entry<K, V> entry : map1.entrySet() ) {
            map2.put( new Key<K>( entry.getKey() , HashCode++ ), entry.getValue());
        }
        map.putAll(map2);
    }

    Set<Entry<K, V>> entrySet()
    {
        Set<Entry<K, V>> entry = new LinkedHashSet<Map.Entry<K,V>>();
        for ( final Entry<Key<K>, V> entry1 : map.entrySet() ) {
            entry.add( new Entry<K, V>(){
                private K Key = entry1.getKey().Key();
                private V Value = entry1.getValue();

                @Override
                public K getKey() {
                    return Key;
                }

                @Override
                public V getValue() {
                    return Value;
                }

                @Override
                public V setValue(V value) {
                    return null;
                }});
        }

        return entry;
    }

    @Override
    public String toString() {
        StringBuilder builder = new  StringBuilder();
        builder.append("{");
        boolean FirstIteration = true;
        for ( Entry<K, V> entry : entrySet() ) {
            builder.append( ( (FirstIteration)? "" : "," ) + ((entry.getKey()==null) ? null :entry.getKey().toString() ) + "=" + ((entry.getValue()==null) ? null :entry.getValue().toString() )  );
            FirstIteration = false;
        }
        builder.append("}");
        return builder.toString();
    }

    class Key<K1>
    {
        K1 Key;
        int HashCode;

        public Key(K1 key, int hashCode) {
            super();
            Key = key;
            HashCode = hashCode;
        }

        public K1 Key() {
            return Key;
        }

        @Override
        public String toString() {
            return  Key.toString() ;
        }

        @Override
        public int hashCode() {

            return HashCode;
        }
    }

Podría también explicar el contexto para el que usted está tratando de implementar un mapa con duplicados de las llaves? Estoy seguro de que podría haber una solución mejor. Los mapas están destinados a mantener las claves únicas por una buena razón. Aunque si realmente quería hacerlo; siempre se puede extender la clase escribir un simple clase de mapa personalizado que tiene una función de amortiguación de choques y que le permitirá mantener múltiples entradas con las mismas teclas.

Nota: Debe implementar la función de amortiguación de choques de tal forma que, las llaves que colisionan se convierten en conjunto único "siempre". Algo tan simple como, llave con código hash objeto o algo anexar?

sólo para estar completa, Apache Commons colecciones también tiene un MultiMap . La desventaja, por supuesto, es que Apache Commons no utiliza medicamentos genéricos.

Con un poco truco que puede utilizar HashSet con duplicados de las llaves. ADVERTENCIA: esta es la implementación en gran medida dependiente de HashSet.

class MultiKeyPair {
    Object key;
    Object value;

    public MultiKeyPair(Object key, Object value) {
        this.key = key;
        this.value = value;
    }

    @Override
    public int hashCode() {
        return key.hashCode();
    }
}

class MultiKeyList extends MultiKeyPair {
    ArrayList<MultiKeyPair> list = new ArrayList<MultiKeyPair>();

    public MultiKeyList(Object key) {
        super(key, null);
    }

    @Override
    public boolean equals(Object obj) {
        list.add((MultiKeyPair) obj);
        return false;
    }
}

public static void main(String[] args) {
    HashSet<MultiKeyPair> set = new HashSet<MultiKeyPair>();
    set.add(new MultiKeyPair("A","a1"));
    set.add(new MultiKeyPair("A","a2"));
    set.add(new MultiKeyPair("B","b1"));
    set.add(new MultiKeyPair("A","a3"));

    MultiKeyList o = new MultiKeyList("A");
    set.contains(o);

    for (MultiKeyPair pair : o.list) {
        System.out.println(pair.value);
    }
}

Si hay duplicados de las llaves luego una tecla puede corresponder a más de un valor. La solución obvia es asignar la clave para una lista de estos valores.

Por ejemplo en Python:

map = dict()
map["driver"] = list()
map["driver"].append("john")
map["driver"].append("mike")
print map["driver"]          # It shows john and mike
print map["driver"][0]       # It shows john
print map["driver"][1]       # It shows mike

He utilizado este:

java.util.List<java.util.Map.Entry<String,Integer>> pairList= new java.util.ArrayList<>();

 1, Map<String, List<String>> map = new HashMap<>();
  

esta solución verbosa tiene varios inconvenientes y es propenso a errores. Eso       implica que necesitamos para crear instancias de una colección para cada valor, la verificación de       su presencia antes de añadir o eliminar un valor, eliminar de forma manual cuando no hay       Los valores se dejan, etcétera.

2, org.apache.commons.collections4.MultiMap interface
3, com.google.common.collect.Multimap interface 

java-map-duplicados teclas

¿qué pasa con un impl tales MultiMap?

public class MultiMap<K, V> extends HashMap<K, Set<V>> {
  private static final long serialVersionUID = 1L;
  private Map<K, Set<V>> innerMap = new HashMap<>();

  public Set<V> put(K key, V value) {
    Set<V> valuesOld = this.innerMap.get(key);
    HashSet<V> valuesNewTotal = new HashSet<>();
    if (valuesOld != null) {
      valuesNewTotal.addAll(valuesOld);
    }
    valuesNewTotal.add(value);
    this.innerMap.put(key, valuesNewTotal);
    return valuesOld;
  }

  public void putAll(K key, Set<V> values) {
    for (V value : values) {
      put(key, value);
    }
  }

  @Override
  public Set<V> put(K key, Set<V> value) {
    Set<V> valuesOld = this.innerMap.get(key);
    putAll(key, value);
    return valuesOld;
  }

  @Override
  public void putAll(Map<? extends K, ? extends Set<V>> mapOfValues) {
    for (Map.Entry<? extends K, ? extends Set<V>> valueEntry : mapOfValues.entrySet()) {
      K key = valueEntry.getKey();
      Set<V> value = valueEntry.getValue();
      putAll(key, value);
    }
  }

  @Override
  public Set<V> putIfAbsent(K key, Set<V> value) {
    Set<V> valueOld = this.innerMap.get(key);
    if (valueOld == null) {
      putAll(key, value);
    }
    return valueOld;
  }

  @Override
  public Set<V> get(Object key) {
    return this.innerMap.get(key);
  }

  @Override
  etc. etc. override all public methods size(), clear() .....

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top