Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
什么';在Java中,按值从映射中删除元素的最快方法是什么?_Java_Performance_Collections - Fatal编程技术网

什么';在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

在Java中,按值从映射中删除元素的最快方法是什么

目前我正在使用:

    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。如果你想优化,你应该找到一种方法将你的价值存储为某种键。如果你不能,你就别无选择