Pregunta

Tengo un millón de filas de datos en formato .txt. El formato es muy simple. Para cada fila:

user1,value1
user2,value2
user3,value3
user1,value4
...

Sabes a lo que me refiero. Para cada usuario, podría aparecer muchas veces, o aparecer solo una vez (nunca se sabe). Necesito encontrar todos los valores para cada usuario. Debido a que el usuario puede aparecer al azar, utilicé Hashmap para hacerlo. Es decir: HashMap (clave: cadena, valor: ArrayList). Pero para agregar datos a arrayList, tengo que usar constantemente HashMap get (key) para obtener arrayList, agregarle valor y luego volver a ponerlo en HashMap. Siento que no es tan eficiente. ¿Alguien sabe una mejor manera de hacer eso?

¿Fue útil?

Solución

No necesita volver a agregar la ArrayList a su Mapa. Si la ArrayList ya existe, simplemente agregue su valor.

Una implementación mejorada podría verse así:

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

mientras procesa cada línea:

String user = user field from line
String value = value field from line

Collection<String> values = map.get(user);
if (values==null) {
    values = new ArrayList<String>();
    map.put(user, values)
}
values.add(value);

Seguimiento de abril de 2014 : escribí la respuesta original en 2009, cuando mi conocimiento de Google Guava era limitado. A la luz de todo lo que hace Google Guava, ahora recomiendo usar su Multimap en lugar de reinventarlo.

Multimap<String, String> values = HashMultimap.create();
values.put("user1", "value1");
values.put("user2", "value2");
values.put("user3", "value3");
values.put("user1", "value4");

System.out.println(values.get("user1"));
System.out.println(values.get("user2"));
System.out.println(values.get("user3"));

Salidas:

[value4, value1]
[value2]
[value3]

Otros consejos

Use Multimap de Google Collections. Permite múltiples valores para la misma clave

https: / /google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html

Los valores de ArrayList en su HashMap son referencias. No es necesario "devolverlo a HashMap". Estás operando en el objeto que ya existe como valor en HashMap.

Si no desea importar una biblioteca.

package util;    

import java.util.ArrayList;    
import java.util.HashMap;    
import java.util.List;    

/**    
 * A simple implementation of a MultiMap. This implementation allows duplicate elements in the the    
 * values. (I know classes like this are out there but the ones available to me didn't work).    
 */    
public class MultiMap<K, V> extends HashMap<K, List<V>> {    

  /**    
   * Looks for a list that is mapped to the given key. If there is not one then a new one is created    
   * mapped and has the value added to it.    
   *     
   * @param key    
   * @param value    
   * @return true if the list has already been created, false if a new list is created.    
   */    
  public boolean putOne(K key, V value) {    
    if (this.containsKey(key)) {    
      this.get(key).add(value);    
      return true;    
    } else {    
      List<V> values = new ArrayList<>();    
      values.add(value);    
      this.put(key, values);    
      return false;    
    }    
  }    
}    

Desde Java 8 puede usar map.computeIfAbsent

https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#computeIfAbsent-K-java.util.function.Function-

Collection<String> values = map.computeIfAbsent(user, k -> new ArrayList<>());
values.add(value);

Creo que lo que quieres es el Multimap. Puede obtenerlo de la colección commons de apache o google-collections.

http://commons.apache.org/collections/

http://code.google.com/p/google-collections/

  

" colección similar a un Mapa, pero   que puede asociar múltiples valores   con una sola llave Si llamas put (K,   V) dos veces, con la misma clave pero   diferentes valores, el multimapa   contiene asignaciones de la clave a ambos   valores. "

No pude encontrar ninguna manera fácil. MultiMap no siempre es una opción disponible. Entonces escribí algo así.

public class Context<K, V> extends HashMap<K, V> {

    public V addMulti(K paramK, V paramV) {
        V value = get(paramK);
        if (value == null) {
            List<V> list = new ArrayList<V>();
            list.add(paramV);
            put(paramK, paramV);
        } else if (value instanceof List<?>) {
            ((List<V>)value).add(paramV);
        } else {
            List<V> list = new ArrayList<V>();
            list.add(value);
            list.add(paramV);
            put(paramK, (V) list);
        }
        return paramV;
    }
}

sería más rápido si utilizaras una LinkedList en lugar de una ArrayList, ya que ArrayList deberá cambiar su tamaño cuando se acerque a su capacidad.

también querrá estimar adecuadamente la capacidad de la colección de envoltura (HashMap o Multimap) que está creando para evitar repeticiones repetitivas.

Como ya se mencionó, MultiMap es su mejor opción.

Dependiendo de los requisitos de su negocio o las restricciones en el archivo de datos, es posible que desee considerar hacer una clasificación única para hacerlo más optimizado para la carga.

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