创建 arraylist 的哈希图的最佳方法
-
06-07-2019 - |
题
我有 100 万行 .txt 格式的数据。格式非常简单。对于每一行:
user1,value1 user2,value2 user3,value3 user1,value4 ...
你知道我的意思。对于每个用户来说,它可能会出现多次,或者只出现一次(你永远不知道)。我需要找出每个用户的所有值。因为user可能会随机出现,所以我使用了Hashmap来做到这一点。那是:哈希映射(键:字符串值:数组列表)。但是要向 arrayList 添加数据,我必须不断使用 HashMap get(key) 来获取 arrayList,为其添加值,然后将其放回 HashMap。我感觉效率不是很高。有人知道更好的方法吗?
解决方案
您无需将ArrayList重新添加回Map。如果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月的后续行动 - 当我对Google Guava的知识有限时,我在2009年写了原始答案。鉴于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]
其他提示
使用Google Collections中的Multimap。它允许同一个键的多个值
https:/ /google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html
HashMap中的ArrayList值是引用。您不需要“将其放回HashMap”。您正在对作为HashMap中的值存在的对象进行操作。
如果您不想导入库。
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;
}
}
}
从 Java 8
开始,您可以使用 map.computeIfAbsent
Collection<String> values = map.computeIfAbsent(user, k -> new ArrayList<>());
values.add(value);
我想你想要的是多重地图。您可以从 apache 的 commons collection 或 google-collections 中获取它。
http://commons.apache.org/collections/
http://code.google.com/p/google-collections/
“收集类似于地图,但可能将多个值与单个密钥相关联。如果您两次调用put(k,v),则使用相同的键,但值不同,则多映射包含从密钥到两个值的映射。”
我找不到任何简单的方法。 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;
}
}
如果使用LinkedList而不是ArrayList会更快,因为ArrayList在接近容量时需要调整大小。
您还需要适当地估计您正在创建的包装集合(HashMap或Multimap)的容量,以避免重复重复。
如前所述, MultiMap
是您的最佳选择。
根据您的业务要求或对数据文件的限制,您可能需要考虑对其进行一次性排序,以使其更适合加载。