Problem overview
The method sellItem gets inventory, a scala.collection.mutable.Map[String, Int] from item names to how many of each item a shop has, and the item a customer just bought. It sells one: the count of item drops by 1, and when it reaches 0 the item is removed from the map. It returns the updated map, and the order of the entries doesn't matter.
For {"apples": 5, "pears": 2} and "apples", apples drop to 4. For {"cups": 1, "plates": 3} and "cups", the last cup is sold, so "cups" disappears and only plates remain. For {"pen": 1} and "pen", the map ends up empty. The constraints promise that item is a key and its count is at least 1.
Approach
Work out the count after the sale first. If it is 0, the item is sold out and its key must go, because a key with a count of 0 would still show up as "in stock" to a contains check. Otherwise the key stays with the smaller count. Two outcomes, so an if and an else.
Step by step
- Compute the count left:
inventory(item) - 1, stored in avalnamedremaining. Reading with parentheses is safe, sinceitemis always a key. - If
remaining == 0, callinventory.remove(item). Key and value both go. - Otherwise, in an
elsebranch, setinventory(item) = remaining. - Return
inventory. Only the entry ofitemchanged, or it is gone.
The solution in Scala
class Solution {
def sellItem(inventory: scala.collection.mutable.Map[String, Int], item: String): scala.collection.mutable.Map[String, Int] = {
val remaining = inventory(item) - 1
if (remaining == 0) {
inventory.remove(item)
} else {
inventory(item) = remaining
}
return inventory
}
}
Details on the Scala:
inventory(item)reads the count and throwsNoSuchElementExceptionfor a missing key. The constraints rule that out here; in other code you would check withcontainsor usegetOrElse.removereturns anOptionwith the old stored value. When the last cup is removed that isSome(1), the count before the sale. The method ignores it.- The two branches of the
ifdo different things and neither gives a value the method uses, so the branches are just statements. Thereturncomes after both.
A trace
Take {"apples": 5, "pears": 2} and "apples". inventory("apples") - 1 is 4, so remaining is 4. It isn't 0, so the else branch runs and inventory("apples") becomes 4; "pears" is never touched. Now take {"cups": 1, "plates": 3} and "cups". Here remaining is 0, so remove("cups") runs, and the map keeps only "plates". In the third example the map becomes empty, and isEmpty on it is true.
The reason to remove instead of leaving a 0 is what the map means. A key with a count of 0 still answers true to contains and still adds to size, so a shop that had sold out would look as if it stocked cups. Removing the key keeps the map equal to the shop's real shelves.
Running it
Results for the three examples, as key: value lines sorted by key, the way the lesson's tests print them:
apples: 4
pears: 2
plates: 3
(nothing: the map is empty)
Edge cases and common mistakes
- Keeping a zero. Writing
inventory(item) = remainingin every case leaves"cups" -> 0in the map. The task wants the key removed. - Comparing the wrong number. The test is on the count after the sale. Testing the old count against 0 never fires, because every count is at least 1.
- Selling from a count of 1 in a bigger map. Other entries are untouched: only the entry of
itemchanges.
