Facebook Pixel

Exercise: Classes & Objects

This exercise puts the classes and objects lesson into code.

Scenario

Model a shopping cart that manages a collection of items with prices and quantities. The cart starts empty and is driven by a list of commands. Each command produces exactly one output line. The cart is responsible for all decisions about its own state — adding items, removing them, computing totals, and counting quantities. No external code reaches into the cart's internals.

Commands

The program reads one command per line and prints one line of output per command.

CommandBehaviorOutput
["add", item, price, qty]Add qty of item at price per unit. If item is already in the cart, increase its quantity by qty."Added <qty> <item>"
["remove", item]Remove item entirely from the cart."Removed <item>", or "<item> not in cart" if the item does not exist
["total"]Report the cumulative price * qty across all items."Total: <sum>"
["count"]Report the total quantity across all items."Items: <sum>"

Prices and quantities are integers.

Example
Input
7
add apple 2 3
add banana 1 5
total
count
add apple 3 2
remove banana
total
Output
Added 3 apple
Added 5 banana
Total: 11
Items: 8
Added 2 apple
Removed banana
Total: 10
Explanation
The first `add apple` inserts apple at price 2 with quantity 3. Adding banana at price 1 with quantity 5 gives a total of (2×3)+(1×5)=11. The `count` reports 3+5=8. The second `add apple` increases apple's quantity to 5 (adding 2 to the existing 3). Removing banana eliminates it entirely. The final `total` is only apple: 2×5=10.

Your task

Implement the skeleton in the editor below so the commands produce the output shown in the example above.

How to approach it

The solution centers on a single ShoppingCart class that owns all item data and exposes it only through four methods.


Define a single ShoppingCart class that owns a private map from item name to price and quantity. The map is the only place item data lives — callers never touch it directly.

Each of the four operations is a method on the class. add checks whether the item already exists: if it does, it updates the quantity; if it does not, it inserts a new entry. remove checks for existence before deleting and returns the appropriate message either way. total and count both iterate the map, summing across all entries. This is the point of the exercise: the logic that reads and modifies the cart's data lives with the data itself, not in the command loop.

The command loop in the skeleton already dispatches each command to the matching method and collects the return value. Your job is to implement the four method bodies so the output matches the specification above.

Solution

The reference design places a single ShoppingCart class at the center. The class stores items in a private map from name to price-and-quantity pair, so the only way item data moves is through the four methods. add checks whether the item already exists and either inserts a fresh entry or increments the existing quantity. remove guards against unknown items before deleting. total and count both iterate the map in a single pass, accumulating their respective sums and returning the formatted line — keeping all cart logic inside the class that owns the data.

1def run_cart(instructions: list[list[str]]) -> list[str]:
2    class ShoppingCart:
3        def __init__(self) -> None:
4            self._items: dict[str, list] = {}  # item -> [price, qty]
5
6        def add(self, item: str, price: int, qty: int) -> str:
7            if item in self._items:
8                self._items[item][1] += qty
9            else:
10                self._items[item] = [price, qty]
11            return f"Added {qty} {item}"
12
13        def remove(self, item: str) -> str:
14            if item not in self._items:
15                return f"{item} not in cart"
16            del self._items[item]
17            return f"Removed {item}"
18
19        def total(self) -> str:
20            s = sum(v[0] * v[1] for v in self._items.values())
21            return f"Total: {s}"
22
23        def count(self) -> str:
24            c = sum(v[1] for v in self._items.values())
25            return f"Items: {c}"
26
27    cart = ShoppingCart()
28    output: list[str] = []
29    for instruction in instructions:
30        command = instruction[0]
31        if command == "add":
32            output.append(cart.add(instruction[1], int(instruction[2]), int(instruction[3])))
33        elif command == "remove":
34            output.append(cart.remove(instruction[1]))
35        elif command == "total":
36            output.append(cart.total())
37        elif command == "count":
38            output.append(cart.count())
39    return output
40
41if __name__ == "__main__":
42    instructions = [input().split() for _ in range(int(input()))]
43    res = run_cart(instructions)
44    for line in res:
45        print(line)
46
1import java.util.ArrayList;
2import java.util.Arrays;
3import java.util.HashMap;
4import java.util.List;
5import java.util.Map;
6import java.util.Scanner;
7
8class Solution {
9    static class ShoppingCart {
10        private Map<String, int[]> items = new HashMap<>(); // item -> [price, qty]
11
12        String add(String item, int price, int qty) {
13            if (items.containsKey(item)) {
14                items.get(item)[1] += qty;
15            } else {
16                items.put(item, new int[]{price, qty});
17            }
18            return "Added " + qty + " " + item;
19        }
20
21        String remove(String item) {
22            if (!items.containsKey(item)) return item + " not in cart";
23            items.remove(item);
24            return "Removed " + item;
25        }
26
27        String total() {
28            int sum = 0;
29            for (int[] v : items.values()) sum += v[0] * v[1];
30            return "Total: " + sum;
31        }
32
33        String count() {
34            int c = 0;
35            for (int[] v : items.values()) c += v[1];
36            return "Items: " + c;
37        }
38    }
39
40    public static List<String> runCart(List<List<String>> instructions) {
41        ShoppingCart cart = new ShoppingCart();
42        List<String> output = new ArrayList<>();
43        for (List<String> instruction : instructions) {
44            String command = instruction.get(0);
45            if (command.equals("add")) {
46                output.add(cart.add(instruction.get(1), Integer.parseInt(instruction.get(2)), Integer.parseInt(instruction.get(3))));
47            } else if (command.equals("remove")) {
48                output.add(cart.remove(instruction.get(1)));
49            } else if (command.equals("total")) {
50                output.add(cart.total());
51            } else if (command.equals("count")) {
52                output.add(cart.count());
53            }
54        }
55        return output;
56    }
57
58    public static List<String> splitWords(String s) {
59        return s.isEmpty() ? List.of() : Arrays.asList(s.split(" "));
60    }
61
62    public static void main(String[] args) {
63        java.util.Scanner scanner = new java.util.Scanner(System.in);
64        int instructionsLength = Integer.parseInt(scanner.nextLine());
65        List<List<String>> instructions = new ArrayList<>();
66        for (int i = 0; i < instructionsLength; i++) {
67            instructions.add(splitWords(scanner.nextLine()));
68        }
69        scanner.close();
70        List<String> res = runCart(instructions);
71        for (String line : res) {
72            System.out.println(line);
73        }
74    }
75}
76
1"use strict";
2
3class ShoppingCart {
4    constructor() {
5        this._items = new Map(); // item -> { price, qty }
6    }
7
8    add(item, price, qty) {
9        if (this._items.has(item)) {
10            this._items.get(item).qty += qty;
11        } else {
12            this._items.set(item, { price, qty });
13        }
14        return `Added ${qty} ${item}`;
15    }
16
17    remove(item) {
18        if (!this._items.has(item)) return `${item} not in cart`;
19        this._items.delete(item);
20        return `Removed ${item}`;
21    }
22
23    total() {
24        let sum = 0;
25        for (const { price, qty } of this._items.values()) sum += price * qty;
26        return `Total: ${sum}`;
27    }
28
29    count() {
30        let c = 0;
31        for (const { qty } of this._items.values()) c += qty;
32        return `Items: ${c}`;
33    }
34}
35
36function runCart(instructions) {
37    const cart = new ShoppingCart();
38    const output = [];
39    for (const instruction of instructions) {
40        const [command, ...args] = instruction;
41        if (command === 'add') {
42            output.push(cart.add(args[0], parseInt(args[1]), parseInt(args[2])));
43        } else if (command === 'remove') {
44            output.push(cart.remove(args[0]));
45        } else if (command === 'total') {
46            output.push(cart.total());
47        } else if (command === 'count') {
48            output.push(cart.count());
49        }
50    }
51    return output;
52}
53
54function splitWords(s) {
55    return s === "" ? [] : s.split(" ");
56}
57
58function* main() {
59    const instructionsLength = parseInt(yield);
60    const instructions = [];
61    for (let i = 0; i < instructionsLength; i++) {
62        instructions.push(splitWords(yield));
63    }
64    const res = runCart(instructions);
65    for (const line of res) {
66        console.log(line);
67    }
68}
69
70class EOFError extends Error {}
71{
72    const gen = main();
73    const next = (line) => gen.next(line).done && process.exit();
74    let buf = "";
75    next();
76    process.stdin.setEncoding("utf8");
77    process.stdin.on("data", (data) => {
78        const lines = (buf + data).split("\n");
79        buf = lines.pop();
80        lines.forEach(next);
81    });
82    process.stdin.on("end", () => {
83        buf && next(buf);
84        gen.throw(new EOFError());
85    });
86}
87
1class ShoppingCart {
2    private _items: Map<string, { price: number; qty: number }> = new Map();
3
4    add(item: string, price: number, qty: number): string {
5        const existing = this._items.get(item);
6        if (existing) {
7            existing.qty += qty;
8        } else {
9            this._items.set(item, { price, qty });
10        }
11        return `Added ${qty} ${item}`;
12    }
13
14    remove(item: string): string {
15        if (!this._items.has(item)) return `${item} not in cart`;
16        this._items.delete(item);
17        return `Removed ${item}`;
18    }
19
20    total(): string {
21        let sum = 0;
22        for (const { price, qty } of this._items.values()) sum += price * qty;
23        return `Total: ${sum}`;
24    }
25
26    count(): string {
27        let c = 0;
28        for (const { qty } of this._items.values()) c += qty;
29        return `Items: ${c}`;
30    }
31}
32
33function runCart(instructions: string[][]): string[] {
34    const cart = new ShoppingCart();
35    const output: string[] = [];
36    for (const instruction of instructions) {
37        const [command, ...args] = instruction;
38        if (command === 'add') {
39            output.push(cart.add(args[0], parseInt(args[1]), parseInt(args[2])));
40        } else if (command === 'remove') {
41            output.push(cart.remove(args[0]));
42        } else if (command === 'total') {
43            output.push(cart.total());
44        } else if (command === 'count') {
45            output.push(cart.count());
46        }
47    }
48    return output;
49}
50
51function splitWords(s: string): string[] {
52    return s === "" ? [] : s.split(" ");
53}
54
55function* main() {
56    const instructionsLength = parseInt(yield);
57    const instructions = [];
58    for (let i = 0; i < instructionsLength; i++) {
59        instructions.push(splitWords(yield));
60    }
61    const res = runCart(instructions);
62    for (const line of res) {
63        console.log(line);
64    }
65}
66
67class EOFError extends Error {}
68{
69    const gen = main();
70    const next = (line?: string) => gen.next(line ?? "").done && process.exit();
71    let buf = "";
72    next();
73    process.stdin.setEncoding("utf8");
74    process.stdin.on("data", (data: string) => {
75        const lines = (buf + data).split("\n");
76        buf = lines.pop() ?? "";
77        lines.forEach(next);
78    });
79    process.stdin.on("end", () => {
80        buf && next(buf);
81        gen.throw(new EOFError());
82    });
83}
84
1#include <algorithm>
2#include <iostream>
3#include <iterator>
4#include <limits>
5#include <sstream>
6#include <string>
7#include <vector>
8
9#include <string>
10#include <vector>
11#include <unordered_map>
12
13class ShoppingCart {
14private:
15    std::unordered_map<std::string, std::pair<int,int>> items; // item -> {price, qty}
16
17public:
18    std::string add(const std::string& item, int price, int qty) {
19        auto it = items.find(item);
20        if (it != items.end()) {
21            it->second.second += qty;
22        } else {
23            items[item] = {price, qty};
24        }
25        return "Added " + std::to_string(qty) + " " + item;
26    }
27
28    std::string remove(const std::string& item) {
29        auto it = items.find(item);
30        if (it == items.end()) return item + " not in cart";
31        items.erase(it);
32        return "Removed " + item;
33    }
34
35    std::string total() {
36        int sum = 0;
37        for (const auto& kv : items) sum += kv.second.first * kv.second.second;
38        return "Total: " + std::to_string(sum);
39    }
40
41    std::string count() {
42        int c = 0;
43        for (const auto& kv : items) c += kv.second.second;
44        return "Items: " + std::to_string(c);
45    }
46};
47
48std::vector<std::string> run_cart(std::vector<std::vector<std::string>> instructions) {
49    ShoppingCart cart;
50    std::vector<std::string> output;
51    for (const auto& instruction : instructions) {
52        const std::string& command = instruction[0];
53        if (command == "add") {
54            output.push_back(cart.add(instruction[1], std::stoi(instruction[2]), std::stoi(instruction[3])));
55        } else if (command == "remove") {
56            output.push_back(cart.remove(instruction[1]));
57        } else if (command == "total") {
58            output.push_back(cart.total());
59        } else if (command == "count") {
60            output.push_back(cart.count());
61        }
62    }
63    return output;
64}
65
66template<typename T>
67std::vector<T> get_words() {
68    std::string line;
69    std::getline(std::cin, line);
70    std::istringstream ss{line};
71    ss >> std::boolalpha;
72    std::vector<T> v;
73    std::copy(std::istream_iterator<T>{ss}, std::istream_iterator<T>{}, std::back_inserter(v));
74    return v;
75}
76
77void ignore_line() {
78    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
79}
80
81int main() {
82    int instructions_length;
83    std::cin >> instructions_length;
84    ignore_line();
85    std::vector<std::vector<std::string>> instructions;
86    for (int i = 0; i < instructions_length; i++) {
87        instructions.emplace_back(get_words<std::string>());
88    }
89    std::vector<std::string> res = run_cart(instructions);
90    for (const std::string& line : res) {
91        std::cout << line << '\n';
92    }
93}
94
1class ShoppingCart
2  def initialize
3    @items = {}  # item -> { price: int, qty: int }
4  end
5
6  def add(item, price, qty)
7    if @items.key?(item)
8      @items[item][:qty] += qty
9    else
10      @items[item] = { price: price, qty: qty }
11    end
12    "Added #{qty} #{item}"
13  end
14
15  def remove(item)
16    return "#{item} not in cart" unless @items.key?(item)
17    @items.delete(item)
18    "Removed #{item}"
19  end
20
21  def total
22    sum = @items.values.sum { |v| v[:price] * v[:qty] }
23    "Total: #{sum}"
24  end
25
26  def count
27    c = @items.values.sum { |v| v[:qty] }
28    "Items: #{c}"
29  end
30end
31
32def run_cart(instructions)
33  cart = ShoppingCart.new
34  output = []
35  instructions.each do |instruction|
36    command = instruction[0]
37    case command
38    when 'add'
39      output << cart.add(instruction[1], instruction[2].to_i, instruction[3].to_i)
40    when 'remove'
41      output << cart.remove(instruction[1])
42    when 'total'
43      output << cart.total
44    when 'count'
45      output << cart.count
46    end
47  end
48  output
49end
50
51if __FILE__ == $0
52  instructions = Array.new(Integer(gets, 10)) { gets.split }
53  res = run_cart(instructions)
54  res.each { |line| puts(line) }
55end
56
Invest in Yourself
Your new job is waiting. 83% of people that complete the program get a job offer. Unlock unlimited access to all content and features.
Go Pro