Problem overview
sellItem receives inventory, an object 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 object. It returns the updated inventory. The item is always a key, and every count is at least 1.
With {"apples": 5, "pears": 2} and "apples" the apples go to 4. With {"cups": 1, "plates": 3} and "cups" the last cup is sold, so "cups" disappears and {"plates": 3} remains. With {"pen": 1} and "pen" the result is the empty object.
Approach
Work out the new count first. Then there are two cases. If nothing is left, the key must go: a count of 0 would leave an item the shop doesn't have still listed. Otherwise the key stays, with its new count. Because the constraints promise that the item exists, reading its count is safe and needs no in check.
Step by step
- Compute the remaining count. A
numberconstantremainingholdsinventory[item] - 1. - Handle sold out. If
remainingis 0, usedelete inventory[item]so the key and its value both go. - Handle the rest. In the
elsebranch, storeremainingunder the keyitem. - Return
inventory. Only the entry ofitemchanged, or is gone.
The solution in TypeScript
class Solution {
sellItem(inventory: { [key: string]: number }, item: string): { [key: string]: number } {
const remaining: number = inventory[item] - 1;
if (remaining == 0) {
delete inventory[item];
} else {
inventory[item] = remaining;
}
return inventory;
}
}
The three examples print:
{ apples: 4, pears: 2 }
{ plates: 3 }
{}
Tracing the second example
For {"cups": 1, "plates": 3} and "cups", remaining is 1 - 1 = 0, so the if branch runs and delete inventory["cups"] removes the entry. The else branch is skipped, and { plates: 3 } comes back. For the first example, remaining is 5 - 1 = 4, which is not 0, so the else branch stores 4 under "apples".
The comparison remaining == 0 is fine for numbers. TypeScript programmers usually prefer ===, which also checks the type; for two numbers the two give the same answer.
Why not delete every zero later?
An inventory that keeps zero counts forces every other part of the program to remember that a key may mean "none left". With the key removed, "is it in stock?" is just item in inventory, and the number of keys is the number of different items on the shelf. Removing the entry as soon as the count hits 0 keeps the data honest.
Edge cases and common mistakes
- Setting the count to 0 instead of deleting. For the pen example,
inventory["pen"] -= 1leaves{ pen: 0 }andObject.keys(inventory).lengthis still 1. The lesson wants the key gone. - Setting the value to
undefined. The key would stay in the object, just like a 0 would. - Forgetting the
else. If the new count is stored even after the delete, the key comes straight back, now with the value 0. - Checking the count before subtracting. Testing
inventory[item] == 1and then usinginventory[item] -= 1in the other branch also works: it gives{ apples: 4, pears: 2 }and{}for the first and third examples. Computingremainingonce and using it in both branches gives one place to read the count. - Other items. Only one key is touched, so
pearsstays at 2 in the first example.
