javapalava
javapalava

Reputation: 695

Removal of Values from a HashMap

In the early stages of learning about collections in java....

Is it possible to remove a value from a HashMap, but leave its corresponding key? And if so, would that be deemed bad practice?

I've written the following test to check:

HashMap<String, String> map = new HashMap<String, String>();

map.put("one", "1");
map.put("two", "2");
map.put("three", "3");

map.values().remove("3");

//try map.get("one").remove("1");

for (String name: map.keySet()){

    String key = name;
        String value = map.get(name);

              System.out.println(key + " " + value);  

}

Hoping it would return:

one 1 two 2 three

but instead it returns:

one 1 two 2

I can't find anything in the javadocs or on here that would help me answer my conundrum (at least that I understand!).

FYI - Reasons behind wanting to do this:

I have a HashMap to store a Person (Key) and a Ticket (Value).

When a Person buys a ticket, they're added to the HashMap so I can reference which people already have a ticket. (They're only allowed one ticket/person).

When a ticket becomes no longer valid, I remove the Key and Value (Person and Ticket) from the Map.

A person may then purchase another Ticket, at which point I create a new Key+Value. If a person was still in my HashMap (but not associated with a Ticket) then I could just find that Key (Person) and add a new Value (Ticket) which I though would be more efficient than deleting them, and then re-adding them each time they want to purchase a ticket?

btw Tickets are mutable, so hence why they're my values. Persons are immutable.

Upvotes: 1

Views: 1445

Answers (7)

bvz
bvz

Reputation: 1

You might need to create your own methods.

public static void removeValue(HashMap<String, String> map, String value)
{
    if(map.containsValue(value))
    {
        String key = getKeyByValue(map, value);
        map.put(key, "");
    }
}

public static String getKeyByValue(Map<String, String> map, String value) 
{
    for (Map.Entry<String, String> entry : map.entrySet()) 
    {
        if (value.equals(entry.getValue())) 
        {
            return entry.getKey();
        }
    }
    return "";
}

You would then implement it like this:

HashMap<String, String> map = new HashMap<String, String>();

map.put("one", "1");
map.put("two", "2");
map.put("three", "3");

removeValue(map, "3");

for(String name: map.keySet())
{
    String key = name;
    String value = map.get(name);
    System.out.println(key + " " + value);  
}

Upvotes: 0

rgettman
rgettman

Reputation: 178253

You could replace the ticket value with a null or an empty string.

But the inefficient operation here is removing the value. The operations get, remove, and put in a HashMap are O(1), because they work with hashing the key. On the contrary, removing a value from a HashMap is O(n), because it must scan through all entries looking for the value to remove.

To remove the ticket value, just remove the person via the key. It is efficient to add the person back to the map with a put later.

If you must remove the ticket value directly, consider using another HashMap keyed by the ticket value.

Upvotes: 0

Josef E.
Josef E.

Reputation: 2219

The reason you are getting:

one 1 two 2

Is because a map is a key value pair. Think of:

[one, 1] [two, 2]

Where between each "[]" is a pair and need each other to be part of the map. I feel as though using a map in this situation would be a bad practice.


If I could suggest an alternative; I would maybe make a Person object to hold the values of the ticket(s). So that way you can have a collection of Person objects.

For Example:

List<Person> people = new ArrayList<Person>();

String ticket = people.get(0).getTicket();

String newTicket = "2"

people.get(1).setTicket(newTicket);

This way you can change and remove the ticket with getters and setters and have a good Object Oriented design.

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726489

Hoping it would return:

one 1 two 2 three

Each map entry has a key and a value. You expect that a map would have only a key but no value for the key of "three", which is not possible. However, you are allowed to have null associated with the key:

one 1 two 2 three null

If a person was still in my HashMap (but not associated with a Ticket) then I could just find that Key (Person) and add a new Value (Ticket) which I though would be more efficient than deleting them, and then re-adding them each time they want to purchase a ticket?

This is a micro-optimization that would create more issues than it solves, because a person with no ticket may be represented in two distinct ways:

  • The map has no entry for the person, or
  • The map has an entry which happens to be null.

This is dangerous, because you will inevitably forget to check the ticket for null. Even if you don't do it right away, you would do it in six month. If you don't do it in six months, someone who maintains your program after you will make this mistake as soon as he touches your code.

In addition, it creates a problem with "lingering" keys: now that the map is a one-way street, once the key is in, it stays there forever. This slows down map searches, and prevents unused key objects from being garbage collected.

That is why you would be better off deleting the entry outright, and re-creating it when (and if) you have to do it.

Upvotes: 1

Marcus Widegren
Marcus Widegren

Reputation: 540

You could associate the key with null, or with some special value "Ticket.invalid()" or something like that. But I really don't think it would do anything for performance. I would simply remove, and then add again. The code will be more clear, which is very important. :)

Upvotes: 0

Juraj
Juraj

Reputation: 778

It is possible when the value replace with null value. But then you must be carefull because NullPointerException.

HashMap<String, String> map = new HashMap<String, String>();

map.put("one", "1");
map.put("two", "2");
map.put("three", "3");

then only replace

map.put("three", null);

Upvotes: 0

Rogelio Trivi&#241;o
Rogelio Trivi&#241;o

Reputation: 6519

try map.put("three", ""); or map.put("three", null);

Upvotes: 0

Related Questions