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?
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.
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.
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;
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.
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)
{
...
}
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
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);
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();
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.
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;
}
}
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í?
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.
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);
}
}
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
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<>();
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
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