remove takes a key
Sometimes an entry has to go: a shop stops selling an item, a player leaves the game. On a MutableMap, remove(key) deletes the key together with its value.
val animals = mutableMapOf("cat" to 4, "dog" to 2, "rabbit" to 1)
animals.remove("rabbit")
println(animals.size)
println(animals)
println("rabbit" in animals)
2
{cat=4, dog=2}
false
The size drops by 1, and the key is no longer found by in.
What remove returns
remove gives back the value it deleted, so you can use it one last time. For a key that isn't in the map it returns null and changes nothing, and it does not throw.
val removed = animals.remove("cat")
println(removed)
println(animals.remove("fish"))
println(animals)
4
null
{dog=2}
Note that the return type is nullable (Int?), which is why a missing key can give null.
val does not mean frozen
animals is a val, and you can still delete from it. A val only stops you from pointing the name at another map; the map itself is a mutable object that can change. Writing animals = mutableMapOf("dog" to 1) on a val is what the compiler rejects, with 'val' cannot be reassigned.
Shorter forms
animals -= "dog"removes a key too. It is the same asanimals.remove("dog")without using the result.animals.clear()removes every entry. The size is 0 afterwards andisEmpty()istrue.
Traps
- Reading a deleted key. After the delete,
animals["rabbit"]isnull, soanimals["rabbit"]!!crashes the program. Check withinfirst. - Deleting while looping. Calling
removeinside aforloop over the same map's keys throws aConcurrentModificationException. Collect what to delete first, or usemap.keys.removeAll { ... }after the loop. - Value, not key.
removeworks on keys. Removing "the animal with count 1" means finding its key first.
Only delete what is there
Since remove on a missing key is harmless, you rarely need a check before it. If you want to act only when something was really removed, test the result or ask first:
val a = mutableMapOf("cat" to 4, "dog" to 2)
if ("dog" in a) a.remove("dog")
println(a)
{cat=4}
There is also a two-argument form, remove(key, value), which deletes the entry only when the key currently holds that value. On {cat=4, dog=2}, remove("cat", 9) returns false and changes nothing, while remove("cat", 4) returns true and removes it.
The exercise
The starter code prints the size, then checks whether "rabbit" is still in the map. The last rabbit went home, so step 1 deletes the key below the first println, and step 2 prints animals.size again. The first line shows 3 and the second shows 2, and the check at the bottom now finds no rabbit key.
val animals = mutableMapOf("cat" to 4, "dog" to 2, "rabbit" to 1)
println(animals.size)
animals.remove("rabbit")
println(animals.size)
if ("rabbit" in animals) {
println("We still have rabbits")
} else {
println("No rabbits left")
}
3
2
No rabbits left
The check at the bottom of the starter code does not change. It runs after the delete, asks "rabbit" in animals, gets false and takes the else branch. If you forget the delete, the same code prints We still have rabbits and the size line shows 3 twice, which is a quick way to see that the step is missing.
Key takeaways
remove(key)deletes the key and its value, and the size drops by 1.- It returns the old value, or
nullfor a missing key. - A
valmap can still lose entries. - After a delete, reading the key gives
null.
