Problem overview
The function sellItem receives inventory, a 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. When the count reaches 0, the item is removed from the map. It returns the updated map.
With {"apples": 5, "pears": 2} and "apples", five apples become four. With {"cups": 1, "plates": 3} and "cups", the last cup is sold, so the key cups disappears. With {"pen": 1} and "pen" the result is an empty map. The constraints promise that item is a key and that every count is at least 1, so reading it is safe.
Approach
Work out what the count will be after the sale, then decide. If it will be 0, the item is sold out and should leave the map entirely, key and value, with the built-in delete. Otherwise store the smaller count. Leaving a key with a count of 0 would be a different result: it would still count as a key of the map.
Why compute remaining first, and not test the current count? Because both branches need the new number: the first one asks whether it is 0, the second one stores it. Working it out once, in a named variable, keeps the rest of the function short and easy to read. Trace the second example: cups has 1, so remaining is 0, and the key is deleted. For the first example apples has 5, so remaining is 4, which differs from 0, so the else branch stores 4.
The two branches also never run together. Exactly one of them changes the map: either the key leaves, or its count gets smaller.
Step by step
- Compute
remaining := inventory[item] - 1. - If
remaining == 0, calldelete(inventory, item). - Otherwise, in an
elsebranch, storeinventory[item] = remaining. - Return
inventory.
The solution in Go
func sellItem(inventory map[string]int, item string) map[string]int {
remaining := inventory[item] - 1
if remaining == 0 {
delete(inventory, item)
} else {
inventory[item] = remaining
}
return inventory
}
As with any map argument, the function changes the caller's map, not a copy, and returns that same map. The call delete(inventory, item) takes the map first and the key second, and nothing is assigned back.
Testing
Printing the result for the statement's examples gives:
map[apples:4 pears:2]
map[plates:3]
map[]
Edge cases and common mistakes
- Setting the count to 0 instead of deleting. With
inventory["pen"] = 0the map ismap[pen:0]and still has length 1. The lesson wants the key gone. - Selling an item that isn't there. The constraints rule it out, but without that promise
inventory[item] - 1would read the zero value and give -1, and the code would store-1under a new key. For unchecked input, test for the key with comma-ok first. - Comparing before subtracting. Checking
inventory[item] == 0instead of the remaining count tests the wrong number: no item ever has a count of 0 before the sale. - Counts above 1. Only the last unit removes the key. Selling from a count of 5 just stores 4.
