Лучший способ создать хэш-карту arraylist - PullRequest
28 голосов
/ 18 июня 2009

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

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

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

Ответы [ 9 ]

64 голосов
/ 18 июня 2009

Вам не нужно повторно добавлять 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]
12 голосов
/ 18 июня 2009

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

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

4 голосов
/ 11 марта 2016

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

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 голосов
/ 18 июня 2009

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

2 голосов
/ 22 марта 2018

С 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);
1 голос
/ 18 июня 2009

я думаю, что вы хотите, это Multimap. Вы можете получить его из коллекции Apache Commons или Google-коллекций.

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

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

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

0 голосов
/ 06 января 2016

Не смог найти ни одного легкого пути. 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;
    }
}
0 голосов
/ 05 октября 2009

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

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

0 голосов
/ 18 июня 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...