Domanda

Ho un milione di righe di dati in formato .txt. il formato è molto semplice. Per ogni riga:

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

Sai cosa intendo. Per ogni utente, potrebbe apparire più volte o apparire una sola volta (non si sa mai). Devo scoprire tutti i valori per ciascun utente. Poiché l'utente può apparire in modo casuale, ho usato Hashmap per farlo. Cioè: HashMap (chiave: String, valore: ArrayList). Ma per aggiungere dati all'arrayList, devo usare costantemente HashMap get (chiave) per ottenere l'arrayList, aggiungere valore ad esso, quindi rimetterlo in HashMap. Penso che non sia molto efficiente. Qualcuno sa un modo migliore per farlo?

È stato utile?

Soluzione

Non è necessario aggiungere nuovamente l'ArrayList alla mappa. Se ArrayList esiste già, aggiungi semplicemente il tuo valore.

Un'implementazione migliorata potrebbe apparire come:

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

durante l'elaborazione di ogni riga:

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

Seguito aprile 2014 : ho scritto la risposta originale nel 2009, quando la mia conoscenza di Google Guava era limitata. Alla luce di tutto ciò che fa Google Guava, ora consiglio di usare il suo Multimap invece di 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"));

Uscite:

[value4, value1]
[value2]
[value3]

Altri suggerimenti

Usa Multimap da Google Collections. Consente più valori per la stessa chiave

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

I valori di ArrayList in HashMap sono riferimenti. Non è necessario " rimetterlo su HashMap " ;. Stai operando sull'oggetto che esiste già come valore in HashMap.

Se non si desidera importare una libreria.

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

Da Java 8 puoi usare 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);

Penso che ciò che vuoi sia la Multimap. Puoi ottenerlo dalla collezione commons di apache o da google-collection.

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

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

  

" collezione simile a una mappa, ma   che può associare più valori   con una sola chiave. Se chiami put (K,   V) due volte, con la stessa chiave ma   valori diversi, la multimappa   contiene mappature dalla chiave ad entrambi   . Valori "

Non sono riuscito a trovare un modo semplice. MultiMap non è sempre un'opzione disponibile. Quindi ho scritto qualcosa di questo.

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

sarebbe più veloce se si usasse un LinkedList invece di un ArrayList, poiché ArrayList dovrà ridimensionare quando si avvicina alla capacità.

vorrai anche stimare in modo appropriato la capacità della raccolta di wrapping (HashMap o Multimap) che stai creando per evitare il ripetersi di nuovo.

Come già accennato, MultiMap è l'opzione migliore.

A seconda delle esigenze aziendali o dei vincoli sul file di dati, potresti prendere in considerazione l'idea di effettuare un ordinamento una tantum di esso, per renderlo più ottimizzato per il caricamento.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top