Question

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

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

Vous savez 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 connaître 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 (key: String, value: ArrayList). Mais pour ajouter des données à arrayList, je dois constamment utiliser HashMap get (clé) pour obtenir le tableau, lui ajouter de la valeur, puis le remettre à HashMap. Je pense que ce n'est pas très efficace. Quelqu'un sait une meilleure façon de faire ça?

Était-ce utile?

La solution

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

Une implémentation améliorée peut 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 d'avril 2014 - J'ai rédigé la réponse originale en 2009, alors que 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"));

Sorties:

[value4, value1]
[value2]
[value3]

Autres conseils

Utilisez Multimap à partir 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

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

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

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

Je pense que ce que vous voulez, c'est le Multimap. Vous pouvez l'obtenir à partir de la collection commons d'apache ou de google-collections.

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

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

  

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

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

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

cela serait plus rapide si vous utilisiez une liste LinkedList au lieu d'une liste ArrayList, car la liste ArrayList devra être redimensionnée lorsqu'elle sera proche de sa capacité.

vous souhaiterez également estimer correctement la capacité de la collection d’emballages (HashMap ou Multimap) que vous créez afin d’éviter un rehachage répétitif.

Comme déjà mentionné, MultiMap est votre meilleure option.

En fonction des exigences de votre entreprise ou des contraintes imposées au fichier de données, vous pouvez envisager de le trier une par une afin d'optimiser son chargement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top