Problem overview
The function sell_item receives inventory, a HashMap from item names to how many of each a shop has, and the item a customer just bought. It sells one: the count of that item drops by 1, and when it reaches 0 the item is removed from the map altogether. The order of the entries doesn't matter.
With {"apples": 5, "pears": 2} and "apples", apples drop to 4. With {"cups": 1, "plates": 3} and "cups", the last cup is sold, so "cups" disappears and only plates remain. The constraints promise that item is always a key and that every count is at least 1.
Approach
Work out the count after the sale, then decide between two outcomes. If nothing is left, delete the key. Otherwise, store the smaller count under the same key. A map that keeps entries with a count of 0 would be wrong here, because the task says a sold-out item leaves the dictionary.
Step by step
- Read the current count with
inventory[&item]and subtract 1, storing the result inremaining. Indexing with&itemborrows the key, soitemstays available. Square brackets are safe here because the item is always in the map. - If
remaining == 0, callinventory.remove(&item). The key and its value both go. - Otherwise, in an
elsebranch, callinventory.insert(item, remaining). The key exists already, soinsertreplaces its value with the new count. This is the one place where the replacing behaviour is what we want. - After the branches, return
inventory. Only the entry ofitemchanged, or it is gone.
The solution in Rust
impl Solution {
fn sell_item(mut inventory: HashMap<String, i32>, item: String) -> HashMap<String, i32> {
let remaining = inventory[&item] - 1;
if remaining == 0 {
inventory.remove(&item);
} else {
inventory.insert(item, remaining);
}
return inventory;
}
}
Notice how item is used. The remove branch borrows it with &item, while the insert branch gives it away. That is allowed because only one branch runs. The number remaining is a plain i32, copied out of the map, so the map isn't borrowed any more when the if starts. If you tried to keep a reference into the map while calling insert, the borrow checker would refuse.
Following two calls
For apples, remaining is 5 - 1 = 4. That isn't 0, so the else branch stores 4 under "apples". For cups, remaining is 1 - 1 = 0, so the if branch deletes "cups", and the map is left with plates only. The pears and plates entries are never touched. Computing remaining first, before any change, keeps the two branches simple, because each one only has to do one thing with a number that is already known.
Edge cases and common mistakes
- The last unit. A count of 1 becomes 0, and the key must be removed. Leaving
"pen": 0in the map is a wrong answer. - Removing at every sale. The
removebelongs only to the sold-out case. - A shop with one item. Selling the only pen leaves an empty map, which prints nothing.
- Using the wrong key type. The map has
Stringkeys, so a lookup needs&item, a reference to aString.
Testing
The lesson's tests print the map as key: value lines sorted by key. Results from running the function:
{"apples": 5, "pears": 2},"apples"printsapples: 4andpears: 2.{"cups": 1, "plates": 3},"cups"prints onlyplates: 3.{"pen": 1},"pen"gives an empty map, so there is no line to print.
