Start learning free

LESSON 562 OF 574 · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

Inventory Item in Swift: private Stock with Checked Methods

Practice O(1) Read the full explanation

A shop keeps track of how many pieces of each item it has: the item's stock. The stock can never go below 0, and it changes only when pieces are sold or new ones arrive. So the stock is a private field, changed only through two methods that check the rules. The item's name has no rules to protect, so it stays a field any code can read.

Implement the class InventoryItem:

  • InventoryItem(name, stock) creates an item with that name and that many pieces in stock. The name is kept in a field name that other code can read.
  • sell(n) sells n pieces. If n is at least 1 and at most the stock, it lowers the stock by n and returns true. Otherwise it changes nothing and returns false: selling 0 pieces, a negative number of pieces, or more pieces than there are in stock is refused.
  • restock(n) adds n pieces to the stock when n is at least 1, and ignores n otherwise. It returns nothing.
  • getStock() returns the stock. It is the only way for other code to read it.

Keep the stock private the way the Access Modifiers lesson does in your language: self._stock in Python (private by convention), a #stock field in JavaScript, and the private keyword in Java, C++, C#, TypeScript, Kotlin, Scala and Swift. In Kotlin and Scala the constructor's second parameter is named initialStock, and the private stock starts at its value.

Each test case creates one item, then applies a list of operations to it, in order. The output has one line per test case: the item's name and a colon, then what each sell and getStock call returns, separated by spaces, with sell's answer printed as True or False. The starter code spells these names the way your language does: get_stock in Python, Sell, Restock and GetStock in C#.

 

Example 1:

Input:
    InventoryItem("Pencil", 5)
    sell(3)
    getStock()
    sell(5)
    getStock()
    restock(10)
    getStock()
Output: Pencil: True 2 False 2 12
Explanation: Selling 3 of the 5 pencils works and leaves 2. Selling 5 more is refused, because only 2 are left,
and the stock stays 2. restock(10) brings it to 12.

Example 2:

Input:
    InventoryItem("Mug", 4)
    sell(4)
    getStock()
    sell(1)
    getStock()
Output: Mug: True 0 False 0
Explanation: Selling all 4 mugs is allowed and leaves 0. With nothing left, even one mug can't be sold.

Example 3:

Input:
    InventoryItem("Lamp", 2)
    sell(0)
    sell(-3)
    restock(0)
    restock(-5)
    getStock()
    restock(1)
    sell(3)
    getStock()
Output: Lamp: False False 2 True 0
Explanation: Selling 0 or -3 lamps is refused, and restocking 0 or -5 lamps is ignored, so the stock is still 2.
After restock(1) there are 3 lamps, and selling all 3 works.

 

Constraints:

  • A name is one word of English letters. 0 <= stock <= 104 when the item is created.
  • -104 <= n <= 104 in every sell and restock.
  • A test case has from 1 to 1000 operations, and at least one of them is a sell or a getStock.
STEP 1 OF 7
    Ctrl + Enter to check

    SWIFT · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

    Inventory Item in Swift, explained

    Problem overview

    A shop tracks how many pieces of each item it has: the item's stock. The stock can never go below 0, and it changes only when pieces are sold or new ones arrive. So the stock is a private property, changed only through two methods that check the rules. The item's name has no rules to protect, so it stays a property that any code can read.

    The class InventoryItem has:

    • InventoryItem(name, stock), which creates an item with that name and that many pieces in stock;
    • sell(_ n:), which sells n pieces. If n is at least 1 and at most the stock, it lowers the stock by n and returns true. Otherwise it changes nothing and returns false: selling 0 pieces, a negative number, or more than there are is refused;
    • restock(_ n:), which adds n pieces when n is at least 1 and ignores it otherwise, returning nothing;
    • getStock(), which returns the stock and is the only way for other code to read it.

    For a pencil item with stock 5: sell(3) returns true and leaves 2. Then sell(5) is refused because only 2 are left, and the stock stays 2. After restock(10) the stock is 12. The lesson's tests print the booleans as True and False.

    Approach

    Each method guards the stock before touching it. A sale is valid only when 1 <= n <= stock, so the method first checks the opposite, n < 1 || n > stock, and returns false straight away. Everything after that check can assume the sale is valid. This "refuse early" shape keeps a refused sale from changing anything, and because the stock only ever drops by at most itself, it can't go below 0.

    Restocking is simpler: add n only if it is at least 1. All methods are O(1).

    Step by step

    1. Declare the name as let name: String. It is let because it never changes, and it has no access modifier, so other code can read it.
    2. Declare the stock as private var stock: Int. Outside the class, item.stock doesn't compile.
    3. Store both parameters in init, with self.name = name and self.stock = stock.
    4. In sell, refuse bad requests first: if n < 1 || n > stock returns false. The comparison with stock is strict: selling exactly the stock is allowed.
    5. Complete the sale: stock -= n, then return true.
    6. In restock, an if n >= 1 adds n to the stock. Zero or a negative number isn't a delivery.
    7. getStock returns stock.

    The solution in Swift

    class InventoryItem {
        let name: String
        private var stock: Int
    
        init(_ name: String, _ stock: Int) {
            self.name = name
            self.stock = stock
        }
    
        func sell(_ n: Int) -> Bool {
            if n < 1 || n > stock {
                return false
            }
            stock -= n
            return true
        }
    
        func restock(_ n: Int) {
            if n >= 1 {
                stock += n
            }
        }
    
        func getStock() -> Int {
            return stock
        }
    }
    

    Using it:

    let p = InventoryItem("Pencil", 5)
    print(p.name)
    print(p.sell(3))
    print(p.getStock())
    print(p.sell(5))
    print(p.getStock())
    p.restock(10)
    print(p.getStock())
    let l = InventoryItem("Lamp", 2)
    print(l.sell(0), l.sell(-3))
    l.restock(0); l.restock(-5)
    print(l.getStock())
    l.restock(1)
    print(l.sell(3), l.getStock())
    
    Pencil
    true
    2
    false
    2
    12
    false false
    2
    true 0
    

    Swift details worth knowing

    • Reading the name works, reading the stock doesn't. p.name is fine. Writing p.stock = 500 outside the class is a compile error: 'stock' is inaccessible due to 'private' protection level.
    • let versus var. The name is let and is set once in init. The stock must change, so it is var.
    • The parameter and the property share a name. In init, stock is the parameter and self.stock is the property. Inside sell, there is no parameter called stock, so stock means the property.
    • || is "or". The condition n < 1 || n > stock is true if either part is true.
    • A method with no return type, like restock, returns nothing, so the call is a statement on its own line.

    Edge cases and common mistakes

    • Selling exactly the whole stock. A mug item with stock 4 and sell(4) returns true and leaves 0. The next sell(1) returns false, and the stock stays 0. Using n >= stock as the refusal would wrongly block the first sale.
    • Selling 0 or a negative number. Both are refused. Without the n < 1 part, sell(-3) would "sell" minus three pieces and raise the stock.
    • Changing the stock before checking. Subtracting first and testing afterwards leaves a refused sale half done.
    • Restocking 0 or less. It must be ignored. Without the if, restock(-5) would lower the stock.
    • Making the stock public would pass many tests but give up the guarantee that it never goes below 0.

    Why return a Bool from sell?

    A sale can fail, and the caller needs to know. Returning true or false lets a shop's code decide what to do next: tell the customer there isn't enough, or offer fewer pieces. The method makes the decision, the caller reacts to it, and in both cases the stock stays valid. restock returns nothing because it has nothing to report: an ignored delivery just changes nothing.

    Also notice that the name is a let: even though other code can read it, nobody can assign a new one, so a read-only property needs no private to be safe.

    Complexity

    Each method compares and adds or subtracts, so it runs in O(1) time. An item stores a name and one integer, which is O(1) beyond the name.

    Testing

    • Pencil with 5: sell(3) gives true, stock 2, sell(5) gives false, stock 2, restock(10), stock 12.
    • Mug with 4: sell(4) gives true, stock 0, sell(1) gives false, stock 0.
    • Lamp with 2: sell(0) and sell(-3) give false, restock(0) and restock(-5) do nothing, stock 2. After restock(1), sell(3) gives true and the stock is 0.
    Keep going with Swift500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free