HackerRank Python (Basic) certification

Shopping Cart

Last checked 2 min read

A small classes question. It checks whether you can store state on an object and make len() work on your own class.

What the question asks

Write two classes:

  • Item(name, price), where name is a string and price is an integer. Both must be readable as plain attributes, for example item.name.
  • ShoppingCart(), created with no arguments. It has add(item) to put an item in the cart, total() to return the sum of the prices of everything in the cart, and calling len(cart) must return the number of items in it.

The same item can be added more than once, and every add call counts. There are at most 5 different items and at most 500 operations.

The stub first reads the item list (name and price per line), then runs commands: add <name>, total and len. It writes the result of each total and len on its own line.

Function to write

shopping_cart.pyPython 3
class Item:
    def __init__(self, name, price): ...

class ShoppingCart:
    def __init__(self): ...
    def add(self, item): ...
    def total(self): ...
    def __len__(self): ...

Solution

shopping_cart.pyPython 3
class Item:
    def __init__(self, name, price):
        self.name = name
        self.price = price


class ShoppingCart:
    def __init__(self):
        self.items = []

    def add(self, item):
        self.items.append(item)

    def total(self):
        return sum(item.price for item in self.items)

    def __len__(self):
        return len(self.items)

How it works

  • Item just stores its name and price.
  • Each ShoppingCart gets its own empty list in __init__. add appends to it, so adding the same item twice puts it in the list twice.
  • total() adds up the price of every item in the list. An empty cart returns 0, because sum of nothing is 0.
  • len(cart) calls cart.__len__(). Returning the length of the list gives the item count, duplicates included.

Mistakes that fail the hidden tests

  • Lists declared on the class instead of in __init__. Writing items = [] directly under class ShoppingCart: creates one list shared by every cart, so a second cart starts with the first cart’s items. The stub happens to build only one cart per test, so this bug can slip through on HackerRank, but it is still wrong and an interviewer will spot it. Create the list inside __init__ with self.items = [].
  • Storing items in a set or a dict keyed by name. That silently ignores the second add of the same item, so both len and total come out too low.
  • No __len__. A method called len or size is not enough. len(cart) raises “object of type ‘ShoppingCart’ has no len()”.
  • Keeping a running total and forgetting to update it. Computing the sum when total() is called is simpler and cannot go out of sync.

Try it on sample data

Input in the stub’s format: three items, then seven commands.

3
bike 1000
headphones 100
phone 500
7
len
add bike
add phone
total
add bike
len
total

Output from my run with a copy of the stub’s loop:

0
1500
3
2500

The cart starts empty (0). Bike plus phone is 1500. After the second bike there are 3 items worth 2500.