在 Java 中按值从 Map 中删除元素的最快方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1335935/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the quickest way to remove an element from a Map by value in Java?
提问by Supertux
What's the quickest way to remove an element from a Map by value in Java?
在 Java 中按值从 Map 中删除元素的最快方法是什么?
Currently I'm using:
目前我正在使用:
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);
}
采纳答案by Kevin
Without using a Bi-directional map (commons-collectionsand google collectionshave them), you're stuck with iterating the Map
不使用双向地图(commons-collections和google collections有它们),你会坚持迭代地图
回答by Nader Shirazie
If you have no way to figure out the key from the DomainObj, then I don't see how you can improve on that. There's no built in method to get the key from the value, so you haveto iterate through the map.
如果您无法从 DomainObj 中找出密钥,那么我看不出您可以如何改进。没有内置方法可以从值中获取键,因此您必须遍历映射。
If this is something you're doing all the time, you might maintain two maps (string->DomainObj and DomainObj->Key).
如果这是您一直在做的事情,您可能会维护两个映射(string->DomainObj 和 DomainObj->Key)。
回答by Tom Hawtin - tackline
If you don't have a reverse map, I'd go for an iterator.
如果您没有反向映射,我会选择迭代器。
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.
}
}
回答by Corazu
You could always use the values collection, since any changes made to that collection will result in the change being reflected in the map. So if you were to call Map.values().remove(valueToRemove) that should work - though I'm not sure if you'll see performance better than what you have with that loop. One idea would be to extend or override the map class such that the backing collection then is always sorted by value - that would enable you to do a binary search on the value which may be faster.
您始终可以使用 values 集合,因为对该集合所做的任何更改都会导致更改反映在地图中。因此,如果您要调用 Map.values().remove(valueToRemove) 应该可以工作 - 尽管我不确定您是否会看到性能比使用该循环时更好。一种想法是扩展或覆盖地图类,以便后备集合始终按值排序 - 这将使您能够对可能更快的值进行二分搜索。
Edit: This is essentially the same as Alcon's answer except I don't think his will work since the entrySet is still going to be ordered by key - in which case you can't call .remove() with the value.
编辑:这与 Alcon 的答案基本相同,但我认为他不会起作用,因为 entrySet 仍将按键排序 - 在这种情况下,您不能使用该值调用 .remove() 。
This is also assuming that the value is supposed to be unique or that you would want to remove any duplicates from the Map as well.
这也假设该值应该是唯一的,或者您也希望从 Map 中删除任何重复项。
回答by Nico
i would use this
我会用这个
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");
edit: because objects are referenced by "pointer" not by value.
编辑:因为对象是通过“指针”而不是值来引用的。
N
N
回答by OscarRyz
I don't think this will happen only once in the lifetime of your app.
我认为这在您的应用程序的生命周期中不会只发生一次。
So what I would do, is to delegate to another object the responsability to maintain a reference to the objects added to that map.
所以我要做的是将维护对添加到该地图的对象的引用的责任委托给另一个对象。
So the next time you need to remove it, you use that "reverse map" ...
所以下次你需要删除它时,你使用那个“反向映射”......
class MapHolder {
private Map<String, DomainObj> originalMap;
private Map<DomainObj,String> reverseMap;
public void remove( DomainObj value ) {
if ( reverseMap.contains( value ) ) {
originalMap.remove( reverseMap.get( value ) );
reverseMap.remove( value );
}
}
}
This is much much faster than iterating.
这比迭代快得多。
Obviously you need to keep them synchronized. But it should not be that hard if you refector your code to have one object being responsible for the state of the map.
显然,您需要保持它们同步。但是如果你反思你的代码让一个对象负责地图的状态,那应该不会那么难。
Remember that in OOP we have objects that have an state and behavior. If your data is passing around variables all over the place, you are creating unnecessary dependencies between objects
请记住,在 OOP 中,我们拥有具有状态和行为的对象。如果你的数据到处传递变量,你就会在对象之间创建不必要的依赖关系
Yes, It will take you some time to correct the code, but the time spent correcting it, will save you a lot of headaches in the future. Think about it.
是的,改正代码会花费你一些时间,但是花在改正代码上的时间,会为你日后省去很多麻烦。想想看。
回答by Brent Writes Code
Like most of the other posters have said, it's generally an O(N) operation because you're going to have to look through the whole list of hashtable values regardless. @tackline has the right solution for keeping the memory usage at O(1) (I gave him an up-vote for that).
就像大多数其他发布者所说的那样,它通常是一个 O(N) 操作,因为无论如何您都必须查看整个哈希表值列表。@tackline 有正确的解决方案,可以将内存使用量保持在 O(1)(我为此投了赞成票)。
Your other option is to sacrifice memory space for the sake of speed. If your map is reasonably sized, you could store two maps in parallel.
您的另一个选择是为了速度而牺牲内存空间。如果您的地图大小合理,您可以并行存储两张地图。
If you have a Map then maintain a Map in parallel to it. When you insert/remove on one map, do it on the other also. Granted this is uglier because you're wasting space and you'll have to make sure the "hashCode" method of DomainObj is written properly, but your removal time drops from O(N) to O(1) because you can lookup the key/object mapping in constant time either direction.
如果你有一个地图,那么维护一个与其平行的地图。在一张地图上插入/删除时,也要在另一张地图上进行。当然这更丑,因为你在浪费空间,你必须确保正确编写了 DomainObj 的“hashCode”方法,但是你的删除时间从 O(N) 下降到 O(1) 因为你可以查找密钥/object 在恒定时间内映射到任一方向。
Not generally the best solution, but if your number one concern is speed, I think this is probably as fast as you're gonna get.
通常不是最好的解决方案,但如果您最关心的是速度,我认为这可能与您将获得的一样快。
==================== Addendum: This essentially what @msaeed suggested just sans the third party library.
==================== 附录:这基本上是@msaeed 建议的,只是没有第三方库。
回答by DKSRathore
We know this situation arise rarely but is extremely helpful. I'll prefer BidiMap
from org.apache.commons.collections.
我们知道这种情况很少发生,但非常有帮助。我更喜欢BidiMap
来自org.apache.commons.collections。
回答by Peter Lawrey
A shorter usage of iterator is to use a values() iterator.
迭代器的简短用法是使用 values() 迭代器。
DomainObj valueToRemove = new DomainObj();
for (Iterator<DomainObj> it = map.values().iterator(); it.hasNext();)) {
if (valueToRemove.equals(it.next())) {
it.remove();
break;
}
}
回答by Jared Levy
Here's the one-line solution:
这是单行解决方案:
map.values().remove(valueToRemove);
That's probably faster than defining your own iterator, since the JDK collection code has been significantly optimized.
这可能比定义您自己的迭代器更快,因为 JDK 集合代码已得到显着优化。
As others have mentioned, a bimap will have faster value removes, though it requires more memory and takes longer to populate. Also, a bimap only works when the values are unique, which may or may not be the case in your code.
正如其他人所提到的,双映射将具有更快的值删除,尽管它需要更多的内存并且需要更长的时间来填充。此外,bimap 仅在值唯一时才有效,这在您的代码中可能是也可能不是。