什么';在Java中,按值从映射中删除元素的最快方法是什么?
在Java中,按值从映射中删除元素的最快方法是什么 目前我正在使用:什么';在Java中,按值从映射中删除元素的最快方法是什么?,java,performance,collections,Java,Performance,Collections,在Java中,按值从映射中删除元素的最快方法是什么 目前我正在使用: DomainObj valueToRemove = new DomainObj(); String removalKey = null; for (Map.Entry<String, DomainObj> entry : map.entrySet()) { if (valueToRemove.equals(entry.getValue())) { r
DomainObj valueToRemove = new DomainObj();
String removalKey = null;
for (Map.Entry<String, DomainObj> entry : map.entrySet()) {
if (valueToRemove.equals(entry.getValue())) {
removalKey = entry.getKey();
break;
}
}
if (removalKey != null) {
map.remove(removalKey);
}
DomainObj valueToRemove=newdomainobj();
字符串removalKey=null;
对于(Map.Entry:Map.entrySet()){
if(valueToRemove.equals(entry.getValue())){
removalKey=entry.getKey();
打破
}
}
if(removalKey!=null){
map.remove(removalKey);
}
如果不使用双向映射(并拥有它们),您将不得不迭代映射如果您无法从DomainObj中找出密钥,那么我看不出您可以如何改进。没有内置的方法从值中获取键,因此必须遍历映射
如果这是您一直在做的事情,您可能会维护两个映射(string->DomainObj和DomainObj->Key)。如果您没有反向映射,我会选择迭代器
DomainObj valueToRemove = new DomainObj();
for (
Iterator<Map.Entry<String, DomainObj>> iter = map.entrySet().iterator();
iter.hasNext();
) {
Map.Entry<String, DomainObj> entry = iter.next();
if (valueToRemove.equals(entry.getValue())) {
iter.remove();
break; // if only want to remove first match.
}
}
DomainObj valueToRemove = new DomainObj();
for (Iterator<DomainObj> it = map.values().iterator(); it.hasNext();)) {
if (valueToRemove.equals(it.next())) {
it.remove();
break;
}
}
DomainObj valueToRemove=newdomainobj();
为了(
迭代器iter=map.entrySet().Iterator();
iter.hasNext();
) {
Map.Entry=iter.next();
if(valueToRemove.equals(entry.getValue())){
iter.remove();
break;//如果只想删除第一个匹配项。
}
}
您可以始终使用“值”集合,因为对该集合所做的任何更改都将导致更改反映在地图中。因此,如果调用Map.values().remove(valueToRemove)应该可以工作,尽管我不确定您是否会看到性能比使用该循环时更好。一个想法是扩展或覆盖map类,使支持集合始终按值排序,这将使您能够对值进行二进制搜索,这可能会更快
编辑:这与Alcon的答案基本相同,只是我认为他的答案不起作用,因为entrySet仍将按键排序-在这种情况下,您不能使用值调用.remove()
这还假设该值应该是唯一的,或者您希望从映射中删除任何重复项。我将使用此选项
Map x = new HashMap();
x.put(1, "value1");
x.put(2, "value2");
x.put(3, "value3");
x.put(4, "value4");
x.put(5, "value5");
x.put(6, "value6");
x.values().remove("value4");
编辑:
因为对象是由“指针”而不是值引用的
N我认为在你的应用程序的生命周期中,这种情况不会只发生一次 所以我要做的是,将维护添加到该地图的对象的引用的责任委托给另一个对象 所以下一次你需要移除它时,你可以使用“反向映射”
类映射持有者{
私人地图原件;
私有地图反向映射;
公共无效删除(DomainObj值){
如果(reverseMap.contains(value)){
原始映射移除(反向映射获取(值));
反向映射移除(值);
}
}
}
这比迭代快得多
显然,你需要让它们保持同步。但是,如果您反射代码,让一个对象负责地图的状态,应该不会那么困难
请记住,在OOP中,对象具有状态和行为。如果数据到处传递变量,则会在对象之间创建不必要的依赖关系
是的,更正代码需要一些时间,但是更正代码所花费的时间将为您将来节省大量的麻烦。想想看 正如大多数其他海报所说,这通常是一个O(N)操作,因为不管怎样,您都必须查看整个哈希表值列表@tackline有一个正确的解决方案,可以将内存使用率保持在O(1)(我投了他一票赞成) 你的另一个选择是为了速度而牺牲内存空间。如果地图大小合理,可以并行存储两个地图 如果你有一张地图,那么保持一张与之平行的地图。在一个地图上插入/删除时,在另一个地图上也要插入/删除。当然,这更难看,因为您在浪费空间,并且必须确保正确编写DomainObj的“hashCode”方法,但是您的删除时间从O(N)下降到O(1),因为您可以在任意方向上以恒定时间查找键/对象映射 一般来说,这不是最好的解决方案,但如果你最关心的是速度,我认为这可能是你能得到的最快速度 ====================
附录:这本质上是@mseed建议的,只是第三方库。我们知道这种情况很少出现,但非常有用。我更喜欢来自的
BidiMap
。迭代器的较短用法是使用values()迭代器
DomainObj valueToRemove = new DomainObj();
for (
Iterator<Map.Entry<String, DomainObj>> iter = map.entrySet().iterator();
iter.hasNext();
) {
Map.Entry<String, DomainObj> entry = iter.next();
if (valueToRemove.equals(entry.getValue())) {
iter.remove();
break; // if only want to remove first match.
}
}
DomainObj valueToRemove = new DomainObj();
for (Iterator<DomainObj> it = map.values().iterator(); it.hasNext();)) {
if (valueToRemove.equals(it.next())) {
it.remove();
break;
}
}
DomainObj valueToRemove=newdomainobj();
for(Iterator it=map.values().Iterator();it.hasNext();){
if(valueToRemove.equals(it.next())){
it.remove();
打破
}
}
以下是单行解决方案:
map.values().remove(valueToRemove);
这可能比定义自己的迭代器要快,因为JDK集合代码已经得到了显著的优化
正如其他人所提到的,bimap将具有更快的值删除速度,尽管它需要更多的内存和更长的填充时间。此外,bimap仅在值唯一时有效,这在代码中可能是也可能不是。正确且快速的一行程序实际上应该是:
while (map.values().remove(valueObject));
有点奇怪,上面的大多数示例都假设valueObject
是唯一的
map.values().removeAll(Collections.singleton(null));
参考,我们可以对java 8执行以下操作:
map.values().removeIf(valueToRemove::equals);
+1推荐谷歌收藏BiMap。它速度更快,但会带来内存开销。或者您可以维护两个映射,这就是这些映射的作用。同意。我要提到的另一件事是,如果您需要经常按值删除,请确保映射是您应该用于场景的实际数据结构。+1。如果你想优化,你应该找到一种方法将你的价值存储为某种键。如果你不能,你就别无选择