32

我有一百万行 .txt 格式的数据。格式非常简单。对于每一行:

用户 1,值 1
用户2,价值2
用户 3,价值 3
用户 1,值 4
...

你知道我的意思。对于每个用户,它可能出现多次,或者只出现一次(你永远不知道)。我需要找出每个用户的所有值。因为用户可能随机出现,所以我使用 Hashmap 来做。即:HashMap(key: String, value: ArrayList)。但是要向arrayList添加数据,我必须不断地使用HashMap get(key)来获取arrayList,给它添加值,然后把它放回HashMap。我觉得效率不是很高。有人知道更好的方法吗?

4

9 回答 9

71

您无需将 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 年4 月跟进- 我在 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]
于 2009-06-18T06:19:53.220 回答
13

使用 Google Collections 中的 Multimap。它允许同一个键有多个值

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

于 2009-06-18T05:21:50.970 回答
6

从 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);
于 2018-03-22T12:20:48.443 回答
4

HashMap 中的 ArrayList 值是引用。您不需要“将其放回 HashMap”。您正在对已作为 HashMap 中的值存在的对象进行操作。

于 2009-06-18T05:21:58.177 回答
4

如果您不想导入库。

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;    
    }    
  }    
}    
于 2016-03-11T15:47:15.363 回答
1

我认为你想要的是Multimap。您可以从 apache 的 commons 集合或 google-collections 中获取它。

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

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

“类似于 Map 的集合,但它可能将多个值与单个键相关联。如果您使用相同的键但不同的值调用 put(K, V) 两次,则多重映射包含从键到两个值的映射。”

于 2009-06-18T05:24:46.317 回答
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;
    }
}
于 2016-01-06T15:59:28.717 回答
-1

如果您使用 LinkedList 而不是 ArrayList 会更快,因为 ArrayList 在接近容量时需要调整大小。

您还需要适当地估计您正在创建的包装集合(HashMap 或 Multimap)的容量,以避免重复重新散列。

于 2009-06-18T05:21:29.533 回答
-1

如前所述,MultiMap是您的最佳选择。

根据您的业务需求或对数据文件的限制,您可能需要考虑对其进行一次性排序,以使其更适合加载。

于 2009-10-05T03:43:16.693 回答