JAVA-加速哈希映射创建
我会尽量说清楚的 我有N个对象列表。每个对象存储一个ID字段和一个值字段JAVA-加速哈希映射创建,java,hashmap,Java,Hashmap,我会尽量说清楚的 我有N个对象列表。每个对象存储一个ID字段和一个值字段 LIST A | ID1 v1 | ID2 v2 | ID3 v3 | LIST B | ID1 v1' | ID2 v2' | ID3 v3' | LIST C | ID1 v1''| ID2 v2''| ID3 v3''| 我需要创建一个哈希映射 Map<Integer,List<Double>> 对于每个列表,我当前使用以下代码: object_
LIST A | ID1 v1 | ID2 v2 | ID3 v3 |
LIST B | ID1 v1' | ID2 v2' | ID3 v3' |
LIST C | ID1 v1''| ID2 v2''| ID3 v3''|
我需要创建一个哈希映射
Map<Integer,List<Double>>
对于每个列表,我当前使用以下代码:
object_list.forEach( v -> {
String id = v.getID();
Double value = v.getValue();
if(map.containsKey(id)){
map.get(id).add(value);
}
else{
List<Double> list = new ArrayList<>();
list.add(value);
map.put(id, list);
}
});
object\u list.forEach(v->{
字符串id=v.getID();
双值=v.getValue();
if(地图容器(id)){
map.get(id).add(value);
}
否则{
列表=新的ArrayList();
列表。添加(值);
地图放置(id、列表);
}
});
我的问题:我能以更快的方式执行此操作吗
谢谢使用番石榴的多重地图会更简单
ListMultimap<Integer, Double> multimap = ArrayListMultimap.create();
如果id存在,则会向其添加值,否则会创建一个新密钥。问题是:为什么您对当前的性能不满意 您是否对当前代码进行了基准测试 这段代码运行的时间是否超过;比如说每分钟10公里 您的用户是否抱怨性能问题;你做了仔细的分析,发现这段代码是罪魁祸首 如果你回答所有这些问题时都没有回答,那么你很可能没有问题 考虑到你在这里真的有问题;当然,基尔托斯的解决方案可能会让人松一口气。但我认为您应该更进一步,研究整个数据流。比如:假设您花费大量时间从现有列表中检索此数据。如果你能避免建立最初的列表,也许你应该进行调查;而是以一种首先需要较少转换工作的方式提供所需的数据
此外:您已经在使用streams。也许你可以在这里平行走 使用Java 8便捷的
computeIfAbsent
方法,您可以非常直观地完成此任务:
objectList.forEach( v -> {
List<Double> doubleList = map.computeIfAbsent(v.getID(), k->new ArrayList<>());
doubleList.add(v.getValue());
});
objectList.forEach(v->{
List doubleList=map.computeIfAbsent(v.getID(),k->newArrayList());
doubleList.add(v.getValue());
});
请注意,这并不一定比原始解决方案运行得更快。它的优点是阅读起来更清晰。如果N个项目意味着它们的数量是固定的,那么您可以创建一个大小相同的地图,当满了地图时,地图不会展开
Map<Integer,List<Double>> map = new HashMap<Integer,List<Double>>(N, 1);
Map-Map=newhashmap(N,1);
不要使用map.containsKey(id)
而只使用map.get(id)
并检查是否为null。您可以使用:map.computeIfAbsent(id,k->new ArrayList()).add(value)
什么叫“更快”?你真的关心性能,还是说“更具表现力”或“更简洁”?我不认为并行性会改善它,但:object\u list.parallelStream().collect(groupingBy(X::getID,mapping(X::getValue,toList())
这是一个完全合适的问题,但它应该是一个注释,而不是答案。是的,我的用户抱怨性能问题。我对我的应用程序进行了基准测试,这一点似乎是瓶颈。在此步骤中,在解压缩操作后从内存中检索数据。我的测试表明,数据检索和数据解压缩需要相同的时间。所以,我开始检查数据检索步骤,以评估是否可以应用某些优化。@fab我运行了一个包含100个键的100万条目的列表,耗时78毫秒。1000万条条目需要更长的时间,但这不会成为代码问题。这将是一个内存优化问题。@Fab如果此步骤需要很长时间,请检查调用v.getID()
和v.getValue()
的时间。你把它们添加到地图上的方式不太可能会花费时间。如果这两个方法调用没有占用太多时间,那么下一步就是调优hashmap。检查HashMap构造函数参数。@Fab另外,如果您可以估计每个ID的列表大小,那么请使用ArrayList构造函数为列表预先分配内存,这将通过避免重新分配和数组复制来加快它的速度。Guava的multimap是一个很好的选择,但它需要修改我项目的所有相关部分。嗯,始终可以使用一行代码将多重映射转换为原始映射:Map foo=multimap.asMap()代码>它实际上可能运行得更快,因为它在内部只执行一次查找,而OP的代码执行两次(containsKey()
和get()
)。@Thomas可能会,但这取决于各种权衡,所以最好不要轻率地宣称。我想这取决于条目的数量。@slim我没有做出任何声明(“可能”跑得更快是这里的关键词)。)删除过时的局部变量时,可以用表达式语法替换块语法:objectList.forEach(v->map.computeIfAbsent(v.getID(),k->new ArrayList()).add(v.getValue())代码>@Holger好吧,你可以,但它对性能没有帮助,而且它使阅读变得稍微困难,那么为什么要这么做呢?Extract变量是一种有用的可读性重构。JIT将优化中间变量。
objectList.forEach( v -> {
List<Double> doubleList = map.computeIfAbsent(v.getID(), k->new ArrayList<>());
doubleList.add(v.getValue());
});
Map<Integer,List<Double>> map = new HashMap<Integer,List<Double>>(N, 1);