2009-06-18 6 views
24

У меня есть миллион строк данных в формате .txt. формат очень прост. Для каждого ряда:Лучший способ создания hashmap arraylist

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

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

ответ

61

Вам не нужно повторно добавлять 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] 
+0

Другие ответы правильные. Я просто не хочу использовать внешние библиотеки. – 2009-06-20 04:12:26

+0

Это была спасательная жизнь, спасибо. – wirbly

-1

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

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

+2

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

4

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

1

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

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

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

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

-1

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

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

+1

Это должен быть комментарий –

0

Я не мог найти простой способ. 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; 
    } 
} 
3

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

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

Хороший пример основного решения Java API. Спасибо, – Loa

Смежные вопросы