Лучший способ создать хэш-карту массива

У меня есть миллион строк данных в формате .txt. формат очень простой. Для каждой строки:

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

Если вы понимаете, о чем я. Для каждого пользователя он может появляться много раз или появляться только один раз (мало ли). Мне нужно узнать все значения для каждого пользователя. Поскольку пользователь может появляться случайным образом, я использовал для этого Hashmap. То есть: HashMap (ключ: String, значение: ArrayList). Но чтобы добавить данные в arrayList, мне приходится постоянно использовать HashMap get(key) для получения arrayList, добавлять к нему значение, а затем возвращать его в HashMap. Я чувствую, что это не очень эффективно. Кто-нибудь знает лучший способ сделать это?


person Community    schedule 18.06.2009    source источник


Ответы (9)


Вам не нужно повторно добавлять ArrayList обратно на карту. Если ArrayList уже существует, просто добавьте в него свое значение.

Улучшенная реализация может выглядеть так:

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

при обработке каждой строки:

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

Последние действия, апрель 2014 г.. Я написал первоначальный ответ еще в 2009 г., когда мои знания о Google Guava были ограничены. В свете всего того, что делает Google Guava, я теперь рекомендую использовать его Multimap вместо того, чтобы изобретать его заново.

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

Выходы:

[value4, value1]
[value2]
[value3]
person Steve Kuo    schedule 18.06.2009
comment
Все остальные ответы верны. Я просто не хочу использовать сторонние библиотеки. - person ; 20.06.2009

Используйте Multimap из Google Collections. Он допускает несколько значений для одного и того же ключа

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

person Yoni Roit    schedule 18.06.2009

Начиная с Java 8 вы можете использовать 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);
person ilopezluna    schedule 22.03.2018

Значения ArrayList в вашем HashMap являются ссылками. Вам не нужно «вернуть его в HashMap». Вы работаете с объектом, который уже существует как значение в HashMap.

person anthony    schedule 18.06.2009

Если вы не хотите импортировать библиотеку.

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;    
    }    
  }    
}    
person Stuart Clark    schedule 11.03.2016

я думаю, что вы хотите, это Multimap. Вы можете получить его из коллекции apache commons или google-collections.

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

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

«коллекция похожа на карту, но может связать несколько значений с одним ключом. Если вы дважды вызываете put (K, V) с одним и тем же ключом, но с разными значениями, мультикарта содержит сопоставления ключа с обоими значениями».

person kctang    schedule 18.06.2009

Я не мог найти простой способ. MultiMap не всегда доступен. Так я написал что-то это.

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;
    }
}
person Ankur    schedule 06.01.2016

было бы быстрее, если бы вы использовали LinkedList вместо ArrayList, так как ArrayList нужно будет изменить размер, когда он приблизится к емкости.

вам также потребуется правильно оценить емкость создаваемой вами коллекции оболочек (HashMap или Multimap), чтобы избежать повторного повторного хеширования.

person akf    schedule 18.06.2009
comment
ArrayList почти наверняка будет иметь лучшую среднюю производительность, даже с изменением размера. LinkedList — хороший выбор, если вы хотите, чтобы все ваши операции занимали примерно одинаковое время, например, они связаны с пользовательским интерфейсом, и вы не хотите случайных задержек, когда ваш пользователь выполняет действие. - person Hank Gay; 28.06.2009

Как уже упоминалось, MultiMap — ваш лучший вариант.

В зависимости от ваших бизнес-требований или ограничений на файл данных вы можете рассмотреть возможность его однократной сортировки, чтобы сделать его более оптимизированным для загрузки.

person aberrant80    schedule 05.10.2009
comment
Это должен быть комментарий - person Stuart Clark; 14.01.2017