web-dev-qa-db-fra.com

Meilleure façon de créer une table de hachage de la liste des tableaux

J'ai un million de lignes de données au format .txt. le format est très simple. Pour chaque ligne:

 utilisateur1, valeur1 
 utilisateur2, valeur2 
 utilisateur3, valeur3 
 utilisateur1, valeur4 
 ... 

Tu sais ce que je veux dire. Pour chaque utilisateur, il peut apparaître plusieurs fois ou apparaître une seule fois (on ne sait jamais). J'ai besoin de trouver toutes les valeurs pour chaque utilisateur. Parce que l'utilisateur peut apparaître au hasard, j'ai utilisé Hashmap pour le faire. C'est-à-dire: HashMap (clé: String, valeur: ArrayList). Mais pour ajouter des données à la arrayList, je dois constamment utiliser HashMap get (key) pour obtenir la arrayList, y ajouter de la valeur, puis la remettre dans HashMap. Je pense que ce n'est pas très efficace. Quelqu'un connaît une meilleure façon de le faire?

28
eric

Vous n'avez pas besoin de rajouter la liste de tableaux à votre carte. Si ArrayList existe déjà, ajoutez-y simplement votre valeur.

Une implémentation améliorée pourrait ressembler à:

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

lors du traitement de chaque ligne:

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

Suivi en avril 2014 - J'ai écrit la réponse originale en 2009 lorsque ma connaissance de Google Guava était limitée. À la lumière de tout ce que fait Google Guava, je recommande maintenant d'utiliser son Multimap au lieu de le réinventer.

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

Les sorties:

[value4, value1]
[value2]
[value3]
64
Steve Kuo

Utilisez Multimap de Google Collections. Il permet plusieurs valeurs pour la même clé

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

12
Yoni Roit

Les valeurs ArrayList dans votre HashMap sont des références. Vous n'avez pas besoin de "le remettre sur HashMap". Vous travaillez sur l'objet qui existe déjà en tant que valeur dans le HashMap.

4
anthony

Si vous ne souhaitez pas importer de bibliothèque.

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;    
    }    
  }    
}    
4
Stuart Clark

Puisque Java 8 vous pouvez utiliser 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);
2
ilopezluna

je pense que ce que vous voulez, c'est le Multimap. Vous pouvez l'obtenir auprès de la collection Apache's commons, ou google-collections.

http://commons.Apache.org/collections/

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

"collection similaire à une Map, mais qui peut associer plusieurs valeurs à une seule clé. Si vous appelez put (K, V) deux fois, avec la même clé mais des valeurs différentes, le multimap contient des mappages de la clé aux deux valeurs."

1
kctang

Je n'ai trouvé aucun moyen facile. MultiMap n'est pas toujours une option disponible. J'ai donc écrit quelque chose.

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