Reputation: 695
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
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
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
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
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:
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
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
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