21

So I have a java hashmap like below:

hMap.put("1", "One");
hMap.put("2", "Two");
hMap.put("3", "Two");

I would like to remove ALL items where the value is "Two"

If I do something like:

hmap.values().remove("Two");

Only the first one is deleted, I want to remove them all, how can this be done?

FrustratedWithFormsDesigner
  • 26,726
  • 31
  • 139
  • 202
Anthony Webb
  • 1,311
  • 4
  • 15
  • 22

6 Answers6

48

hmap.values().removeAll(Collections.singleton("Two"));

EDIT: the (significant) disadvantage with this concise approach is that you are basically forced to comment it, saying something like

// remove("Two") would only remove the first one

otherwise, some well-meaning engineer will try to simplify it for you someday and break it. This happens... sometimes the well-intentioned do-gooder is even Future You!

Kevin Bourrillion
  • 40,336
  • 12
  • 74
  • 87
  • This looks good kevin, is there any way to write a debug line above to tell which keys are about to be whacked? – Anthony Webb Apr 07 '10 at 18:59
  • You might want to look into Ron's solution (or mine, if you're willing to add google-collections) if you need to log removed keys. – Jon Quarfoth Apr 07 '10 at 19:32
  • Yep, Ron's and Jon's (ha) answers are both viable if you want to know the keys you're whacking. I would tend to prefer Ron's, which traverses the map only once. – Kevin Bourrillion Apr 08 '10 at 05:07
  • Kevin, your last sentence make me think you already fell into the trap left by the Past-you :p – Alex Jul 20 '16 at 12:46
  • Rather than being forced to add a comment, adding a unit test would also help to "document" the reason for requiring removeAll – Graeme Moss Nov 20 '18 at 12:14
26

In Java 8

hmap.values().removeIf(val -> "Two".equals(val));
gpanders
  • 1,301
  • 2
  • 15
  • 23
16
for (Iterator<Map.Entry<String,String>> it = hMap.entrySet().iterator(); it.hasNext();) {
 Map.Entry<String,String> e = it.next();
 if ("Two".equals(e.getValue())) {
  it.remove();
 }
}

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
Ron
  • 1,932
  • 20
  • 17
11

You can use while( hmap.values().remove("Two") ); since the remove call returns true if the collection was changed as a result of the call.

sgtFloyd
  • 997
  • 1
  • 9
  • 18
  • this works very well, and i think is a good part of the reason why remove() returns boolean. – chris Apr 07 '10 at 16:30
  • 5
    @Anthony: Kevin is talking about worst-case performance. See http://en.wikipedia.org/wiki/Big_O_notation#Orders_of_common_functions To answer without (much) math - this solution will iterate through the elements of map n+1 times, where n is the number of values that are removed. Another solution, say Kevin's or Ron's, will only iterate through the values in the Map once. The runtime of the method would be much slower using this solution, if you were operating on very large maps. – Jon Quarfoth Apr 07 '10 at 19:07
6

(Updated solution for logging of removed values)

This solution uses the google-collections library [LINK]

import static com.google.common.collect.Maps.filterValues;
import static com.google.common.base.Predicates.equalTo;

...

Map<String, String> removedValues = filterValues(hMap, equalTo("Two"));      
System.out.println(removedValues); //Log Removed Values
removedValues.clear(); //Removes from original map, since this is a view.

Note - This solution takes advantage of the fact that the Map returned by the filterValues call is a view of the elements in the original HashMap. This allows us to examine them and log out the keys that were removed, and then remove them from the original map with a simple call to clear().

You may have reasons for not wanting to use the google-collections library in your project, but if you don't, I'd suggest checking it out.

Jon Quarfoth
  • 2,129
  • 16
  • 20
2

You have to iterate through the list, look at the value object, and conditionally do the remove. Note you'll get an exception if you try to remove an object while iterating over a HashMap. Would have to make a copy of the map or use ConcurrentHashMap.

Marcus Leon
  • 55,199
  • 118
  • 297
  • 429