Implementación de mapas con claves duplicadas


Quiero tener un mapa con claves duplicadas.

Sé que hay muchas implementaciones de mapas (Eclipse me muestra alrededor de 50), así que apuesto a que debe haber una que lo permita. Sé que es fácil escribir su propio mapa que hace esto, pero preferiría usar alguna solución existente.

Tal vez algo en commons-collections o google-collections?

Author: Matthias Braun, 2009-06-30

16 answers

Está buscando un multimap, y de hecho tanto commons-collections como Guava tienen varias implementaciones para eso. Multimaps permite múltiples claves manteniendo una colección de valores por clave, es decir, puede poner un solo objeto en el mapa, pero recupera una colección.

Si puedes usar Java 5, preferiría el de Guayaba Multimap como es genérico-consciente.

 76
Author: nd.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-29 10:25:11

No necesitamos depender de la biblioteca externa de Google Collections. Simplemente puede implementar 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 afinar el código.

 29
Author: user668943,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-28 13:06:43
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: necesitamos importar archivos de 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;
 23
Author: Issac Balaji,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-06 15:47:42

Simplemente podría pasar una matriz de valores para el valor en un HashMap regular, simulando así claves duplicadas, y dependería de usted decidir qué datos usar.

También puedes usar un MultiMap, aunque no me gusta la idea de duplicar claves.

 17
Author: AlbertoPL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-30 10:43:56

Si desea iterar sobre una lista de pares clave-valor (como escribió en el comentario), entonces una Lista o una matriz debería ser mejor. Primero combine 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;
   }

}

Reemplace Class1 y Class2 con los tipos que desea usar para claves y valores.

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

Pair[] pairs = new Pair[10];
...
for (Pair pair : pairs)
{
   ...
}
 10
Author: Mnementh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-30 10:51:58
commons.apache.org

MultiValueMap class
 5
Author: Ravi Parekh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-08 11:54:24

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

 4
Author: Thach Van,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-22 22:40:53

Aprende de mis errores...por favor, no implemente esto por su cuenta. Guava multimap es el camino a seguir.

Una mejora común requerida en multimaps es no permitir pares de claves-valores duplicados.

Implementar/cambiar esto en su implementación puede ser molesto.

En Guayaba es tan simple como:

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

ArrayListMultimap<String, Integer> allow_dupe_key_plus_val = ArrayListMultimap.create();
 3
Author: frostbite,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-08 18:29:51

Tenía una variante ligeramente diferente de este problema: Se requería asociar dos valores diferentes con la misma clave. Simplemente publicándolo aquí en caso de que ayude a otros, 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, la clave Framid se lee de la primera cadena de un archivo de entrada en cada línea, el valor de frameTypeHash se construye dividiendo la línea restante y se almacena como objeto de cadena originalmente, durante un período de tiempo en el que el archivo comenzó a tener varias líneas (con diferentes valores) asociados con la misma clave Framid, por lo que frameTypeHash se sobrescribió con la última línea como valor. Reemplazé el objeto String con otro objeto HashMap como campo de valor, esto ayudó a mantener una sola clave para diferentes asignaciones de valores.

 1
Author: Suresh Vadali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-02 12:40:59
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;
        }
    }
 1
Author: Gabrial David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-01 08:03:56

¿Podría explicar también el contexto para el que está intentando implementar un mapa con claves duplicadas? Estoy seguro de que podría haber una solución mejor. Los mapas están destinados a mantener claves únicas por una buena razón. Aunque si realmente lo desea, siempre puede extender la clase escribir una clase de mapa personalizado simple que tiene una función de mitigación de colisión y le permitiría mantener varias entradas con las mismas claves.

Nota: Debe implementar la función de mitigación de colisiones de tal manera que, las claves que chocan se convierten en un conjunto único "siempre". Algo simple como, anexando clave con objeto hashcode o algo así?

 0
Author: Priyank,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-30 10:41:32

Solo para estar completo, Apache Commons Collections también tiene un MultiMap. La desventaja por supuesto es que Apache Commons no usa genéricos.

 0
Author: newacct,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-30 19:30:25

Con un poco de hackeo se puede utilizar HashSet con claves duplicadas. ADVERTENCIA: esto depende en gran medida de la implementación del 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);
    }
}
 0
Author: Erdem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-13 13:11:43

Si hay claves duplicadas, una clave puede corresponder a más de un valor. La solución obvia es asignar la clave a 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
 0
Author: cyberthanasis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-08 18:29:07

Usé esto:

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

 0
Author: Alex Arvanitidis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-02 16:28:33
 1, Map<String, List<String>> map = new HashMap<>();

Esta solución detallada tiene múltiples inconvenientes y es propensa a errores. Se implica que necesitamos instanciar una colección para cada valor, comprobar si su presencia antes de agregar o eliminar un valor, elimínelo manualmente cuando no los valores se dejan, etcétera.

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

Java-map-duplicate-keys

 0
Author: Vicky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-29 11:27:15