Problem overview
The method addContact gets a phone book, phoneBook, a scala.collection.mutable.Map[String, String] from names to phone numbers, plus a name and a phone number. It adds the name with its number and returns the phone book, but only when the name isn't a key yet. A name that is already there keeps its old number. The order of the entries doesn't matter.
With {"Ana": "555-0142", "Ben": "555-0199"} and the new contact "Cara", "555-0123", the book gets a third entry. Adding "Ben" with "555-0100" changes nothing, because Ben already has "555-0199". An empty phone book plus "Max" gives a book with one contact.
Approach
Assigning to a key with phoneBook(name) = number adds the entry if the key is new, but it also replaces the value if the key exists. The task forbids that replacement, so the assignment must run only for a new name. phoneBook.contains(name) says whether the name is a key, and ! turns it around.
Step by step
- Write an
ifon!phoneBook.contains(name). It is true only when the name is not a key yet. Close its brace right away and fill the body next. - Inside it, assign
phoneBook(name) = number. For a key that isn't there, this adds it with its value. - After the
if, returnphoneBook. It has the new contact, or it is as it was.
The solution in Scala
class Solution {
def addContact(phoneBook: scala.collection.mutable.Map[String, String], name: String, number: String): scala.collection.mutable.Map[String, String] = {
if (!phoneBook.contains(name)) {
phoneBook(name) = number
}
return phoneBook
}
}
Details on the Scala:
phoneBook(name) = numberis shorthand forphoneBook.update(name, number). It needs a mutable map; an immutableMaphas no such operation.containslooks only at the keys. Two people may share a number, and that is fine: numbers are values, not keys.- The method changes the map it receives and returns that same map.
Another way
Scala's mutable map has getOrElseUpdate(key, default). It returns the value for the key, and when the key is missing it stores the default first. So phoneBook.getOrElseUpdate(name, number) adds the contact only when the name is new, which is the same behaviour in one call. With the first two examples it gives Ana: 555-0142, Ben: 555-0199, Cara: 555-0123, and Ben keeps 555-0199 after getOrElseUpdate("Ben", "555-0100"). The lesson's version spells the check out with contains, which makes each step visible.
Why the check matters
Think of the phone book as a record of who was added first. Overwriting would silently lose the old number, and nothing in the program would say so. A check before every write is the cheap way to protect existing data: ask whether the key is there, and write only if the answer is no.
Running it
Results for the three examples, one entry per line, sorted by name (the order of entries in a map isn't fixed, so the lesson's tests don't depend on it):
Cara added:
Ana: 555-0142
Ben: 555-0199
Cara: 555-0123
Ben again:
Ana: 555-0142
Ben: 555-0199
Empty book, Max:
Max: 555-0100
Edge cases and common mistakes
- Skipping the check. Without the
if,phoneBook("Ben") = "555-0100"overwrites the old number. That is the main trap: the assignment looks safe, but for an existing key it replaces the value. - Forgetting
!. The assignment then runs only for names already in the book, and a new name is never added. - An empty book. Nothing special is needed:
containsisfalse, so the contact is added. - Checking the number. The test is on the name. Two contacts with the same number are both kept.
