studio programacion para móviles libro edición desarrollo desarrollar curso aprende aplicaciones java duplicates guava multimap

java - para - manual de programacion android pdf



Implementación del mapa con claves duplicadas (15)

¿Podría explicar también el contexto para el cual está tratando de implementar un mapa con claves duplicadas? Estoy seguro de que podría haber una mejor solución. Los mapas están destinados a mantener claves únicas por una buena razón. Aunque si realmente quisieras hacerlo; siempre puede extender la clase escribir una clase de mapa personalizada simple que tenga una función de mitigación de colisión y le permita mantener múltiples entradas con las mismas claves.

Nota: Debe implementar la función de mitigación de colisión de modo que las claves colisionantes se conviertan en un conjunto único "siempre". ¿Algo simple como, agregar clave con código hash de objeto o algo así?

Quiero tener un mapa con claves duplicadas.

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

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


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 duplicar pares de claves y valores.

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

En Guava es tan simple como:

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


Con un poco de hack puede usar HashSet con claves duplicadas. ADVERTENCIA: esto depende en gran medida de la implementación 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); } }


Está buscando una multimapa, y de hecho ambas colecciones comunes y Guava tienen varias implementaciones para eso. Las multimapas permiten varias 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 puede usar Java 5, preferiría el Multimap de Guava ya que es genérico.


Este problema se puede resolver con una lista de entrada de mapa List<Map.Entry<K,V>> . No necesitamos usar ni bibliotecas externas ni 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);


No es necesario que dependamos 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 ajustar el código.


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) { ... }


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


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

También puede utilizar un MultiMap , aunque no me gusta la idea de duplicar las claves.


Tuve una variante ligeramente diferente de este problema: se requería asociar dos valores diferentes con la misma clave. Solo publicarlo aquí en caso de que ayude a otros, he introducido un HashMap como 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 la primera cadena del archivo de entrada en cada línea, el valor de frameTypeHash se construye dividiendo la línea restante y se almacenó como objeto String originalmente, durante un período de tiempo el archivo comenzó a tener múltiples líneas ( con diferentes valores) asociado con la misma clave frameID, por lo que frameTypeHash se sobrescribió con la última línea como valor. Reemplacé el objeto String con otro objeto HashMap como el campo de valor, esto ayudó a mantener una sola clave para el mapeo de valores diferentes.


Usé esto:

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


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


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


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


commons.apache.org MultiValueMap class