Wayfair Machine Coding Practice 2

LeetCode Discuss Post: Order Management System (Shopping Cart)

1️⃣ Object-Oriented Approach (OOP)

Problem Statement:

Design an Order Management System for an e-commerce platform with the following features:

  • Add items to the cartaddItemToCart(userId, itemId, quantity)
  • Remove items from the cartremoveItemFromCart(userId, itemId)
  • Calculate the total pricecalculateTotal(userId)
  • Apply tax (10%) and discounts (5% off if total > $100)
  • Checkout the cartcheckout(userId)

Constraints:

  • The system should handle multiple users independently.
  • Invalid item IDs should throw an error.
  • Orders above $100 should get a 5% discount.
  • Prices are predefined in the system.

My Solution (Java)

This implementation supports multiple users using a HashMap to store each user's cart. It provides essential shopping cart functionalities with tax and discount calculations.

import java.util.*;

class ShoppingCart {
    int userId;
    HashMap<Integer, Integer> cart; // (itemId, quantity)
    
    private static final Map<Integer, Double> prices = new HashMap<>();
    static {
        prices.put(101, 120.40);
        prices.put(102, 60.50);
        prices.put(103, 140.20);
        prices.put(104, 20.60);
    }

    ShoppingCart(int userId) {
        this.userId = userId;
        cart = new HashMap<>();
    }

    public void addItemToCart(int itemId, int quantity) {
        if (!prices.containsKey(itemId))
            throw new IllegalArgumentException("Invalid Item Id!");
        if (quantity <= 0)
            throw new IllegalArgumentException("Invalid Quantity!");
        cart.put(itemId, cart.getOrDefault(itemId, 0) + quantity);
        System.out.println("User " + userId + " added " + quantity + " of item " + itemId);
    }

    public void removeItemFromCart(int itemId) {
        if (!cart.containsKey(itemId))
            throw new IllegalArgumentException("Item Id Not in Cart!");
        int qty = cart.get(itemId);
        if (qty > 1) {
            cart.put(itemId, qty - 1);
            System.out.println("User " + userId + " removed " + itemId + ", final qty=" + (qty - 1));
        } else {
            cart.remove(itemId);
            System.out.println("User " + userId + " removed " + itemId);
        }
    }

    public double calculateTotal() {
        double total = 0;
        for (Map.Entry<Integer, Integer> entry : cart.entrySet()) {
            int itemId = entry.getKey();
            int qty = entry.getValue();
            double price = prices.get(itemId);
            total += price * qty;
        }
        if (total > 100) total *= 0.95; // Apply 5% discount if total > $100
        return total;
    }

    public void checkout() {
        if (cart.isEmpty())
            throw new IllegalStateException("Cart is Empty!");
        double total = calculateTotal();
        double tax = 0.10 * total; // Apply 10% tax
        double finalAmount = total + tax;
        System.out.println("User " + userId + " - Total amount = $" + String.format("%.2f", finalAmount));

        try {
            Thread.sleep(200); // Simulate payment processing
        } catch (InterruptedException e) {
            System.out.println("Error: Payment interrupted!");
        }

        cart.clear();
        System.out.println("User " + userId + " - Order placed successfully!");
    }

    public void viewCart() {
        if (cart.isEmpty()) {
            System.out.println("User " + userId + " - Cart is Empty!");
            return;
        }
        System.out.println("User " + userId + "'s Cart:");
        for (Map.Entry<Integer, Integer> entry : cart.entrySet()) {
            System.out.println("Item " + entry.getKey() + " | Quantity: " + entry.getValue() + " | Price: $" + prices.get(entry.getKey()));
        }
    }
}

class OrderManagementSystem {
    private static final Map<Integer, ShoppingCart> userCarts = new HashMap<>();

    public static ShoppingCart getUserCart(int userId) {
        if (!userCarts.containsKey(userId)) {
            userCarts.put(userId, new ShoppingCart(userId));
        }
        return userCarts.get(userId);
    }

    public static void main(String[] args) {
        ShoppingCart user1cart = getUserCart(1);
        user1cart.addItemToCart(101, 4);
        user1cart.addItemToCart(102, 3);
        user1cart.addItemToCart(104, 2);
        user1cart.removeItemFromCart(101);
        user1cart.viewCart();
        user1cart.checkout();

        System.out.println("\n--- New User Session ---\n");

        ShoppingCart user2cart = getUserCart(2);
        user2cart.addItemToCart(103, 1);
        user2cart.addItemToCart(104, 5);
        user2cart.viewCart();
        user2cart.checkout();
    }
}

💡 Explanation

Supports multiple users: userCarts ensures each user has their own shopping cart.
Efficient operations: Uses HashMap for fast lookups.
Discounts & Tax applied: 5% discount for orders over $100 and 10% tax at checkout.
Thread.sleep() to simulate payment processing.


📌 Sample Output

User 1 added 4 of item 101
User 1 added 3 of item 102
User 1 added 2 of item 104
User 1 removed 101, final qty=3
User 1's Cart:
Item 101 | Quantity: 3 | Price: $120.4
Item 102 | Quantity: 3 | Price: $60.5
Item 104 | Quantity: 2 | Price: $20.6
User 1 - Total amount = $529.93
User 1 - Order placed successfully!

--- New User Session ---

User 2 added 1 of item 103
User 2 added 5 of item 104
User 2's Cart:
Item 103 | Quantity: 1 | Price: $140.2
Item 104 | Quantity: 5 | Price: $20.6
User 2 - Total amount = $184.14
User 2 - Order placed successfully!

🔥 Final Thoughts

This solution is clean, efficient, and scalable. It properly supports multiple users, cart operations, and checkout processing.


INTERVIEW -
Got something similar to this in the interview:

import java.util.*;

interface IOrder {
    String getName();
    double getPrice();
    void setName(String name);
    void setPrice(double price);
}

class Order implements IOrder {
    private String name;
    private double price;

    public Order(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() { return name; }
    public double getPrice() { return price; }
    public void setName(String name) { this.name = name; }
    public void setPrice(double price) { this.price = price; }
}

interface IOrderManagement {
    void addOrder(String itemName, Order order);
    void removeOrder(String itemName);
    int calculateTotalDiscountedPrice();
    Map<String, Integer> getCategoryDiscounts();
    void countDuplicateOrders();
    Map<String, Integer> showCart();  // ✅ Returns cart instead of printing
}

class OrderManagement implements IOrderManagement {
    private final HashMap<String, Order> orders = new HashMap<>(); // Stores itemName -> Order
    private final HashMap<String, Integer> cart = new HashMap<>(); // Stores itemName -> quantity
    private final HashMap<String, Integer> categoryDiscounts = new HashMap<>(); // Stores "Cheap" -> 10, "Moderate" -> 20, "Expensive" -> 30

    public void addOrder(String itemName, Order order) {
        orders.put(itemName, order);
    }

    public void removeOrder(String itemName) {
        if (!orders.containsKey(itemName)) {
            System.out.println("Order " + itemName + " not found in the cart.");
            return;
        }
        orders.remove(itemName);
        cart.remove(itemName);
        System.out.println("Order " + itemName + " removed.");
    }

    public Map<String, Integer> getCategoryDiscounts() {
        Map<String, Integer> categoryMap = new HashMap<>();
        categoryMap.put("Cheap", 10);
        categoryMap.put("Moderate", 20);
        categoryMap.put("Expensive", 30);
        return categoryMap;
    }

    private String getCategory(double price) {
        return price < 10 ? "Cheap" : (price <= 20 ? "Moderate" : "Expensive");
    }

    public void countDuplicateOrders() {
        for (String item : orders.keySet()) {
            cart.put(item, cart.getOrDefault(item, 0) + 1);
        }
    }

    public int calculateTotalDiscountedPrice() {
        int totalDiscountedPrice = 0;
        Map<String, Integer> categoryDiscounts = getCategoryDiscounts();

        for (Map.Entry<String, Integer> entry : cart.entrySet()) {
            String item = entry.getKey();
            int quantity = entry.getValue();
            double price = orders.get(item).getPrice();
            String category = getCategory(price);
            int discountRate = categoryDiscounts.get(category);
            int discountedPrice = (int) Math.round(price * (1 - discountRate / 100.0));

            totalDiscountedPrice += discountedPrice * quantity;
        }

        return totalDiscountedPrice;
    }

    public Map<String, Integer> showCart() {  // ✅ Returns cart instead of printing
        return new HashMap<>(cart);
    }
}

class Solution {
    public static void main(String[] args) {
        OrderManagement system = new OrderManagement();

        // Sample Input
        system.addOrder("Order-1", new Order("Order-1", 49));
        system.addOrder("Order-2", new Order("Order-2", 30));
        system.addOrder("Order-3", new Order("Order-3", 15));
        system.addOrder("Order-4", new Order("Order-4", 7));

        // Count duplicate items (as done at the end in your interview)
        system.countDuplicateOrders();

        // Output
        System.out.println("Cart Contents: " + system.showCart());  // ✅ Returns map
        System.out.println("Discounted Price: $" + system.calculateTotalDiscountedPrice());

        // Get category discounts
        Map<String, Integer> categoryDiscounts = system.getCategoryDiscounts();
        System.out.println("Category Discounts: " + categoryDiscounts);

        // Removing an order
        system.removeOrder("Order-2");
        System.out.println("Cart Contents after removal: " + system.showCart());  // ✅ Returns map
        System.out.println("Discounted Price after removal: $" + system.calculateTotalDiscountedPrice());
    }
}

Feedback - You could use something basic like array of objects or something to make it easier. Using the feedback-

📌 Optimized Wayfair Order Management System (Using ArrayList<Order> Instead of HashMap)

🔹 Key Changes Based on Your Request:

Uses List<Order> (ArrayList) instead of Map<String, Order> → Allows duplicate orders naturally.
Uses an enum for category discounts instead of HashMap<String, Integer> → Improves readability & structure.
Implements all interface methods properly.
Maintains showCart() to return Map<String, Integer> (name → quantity).


📌 Updated Java Implementation

import java.util.*;

interface IOrder {
    String getName();
    double getPrice();
    void setName(String name);
    void setPrice(double price);
}

class Order implements IOrder {
    private String name;
    private double price;

    public Order(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() { return name; }
    public double getPrice() { return price; }
    public void setName(String name) { this.name = name; }
    public void setPrice(double price) { this.price = price; }
}

// ✅ Using Enum Instead of HashMap for Discounts
enum DiscountCategory {
    CHEAP(10), MODERATE(20), EXPENSIVE(30);
    private final int discount;

    DiscountCategory(int discount) { this.discount = discount; }
    public int getDiscount() { return discount; }

    public static DiscountCategory getCategory(double price) {
        if (price < 10) return CHEAP;
        if (price <= 20) return MODERATE;
        return EXPENSIVE;
    }
}

interface IOrderManagement {
    void addOrder(String itemName, Order order);
    void removeOrder(String itemName);
    int calculateTotalDiscountedPrice();
    List<String> getCategoryDiscounts();
    void countDuplicateOrders();
    Map<String, Integer> showCart();
}

class OrderManagement implements IOrderManagement {
    private final List<Order> orders = new ArrayList<>(); // ✅ Using `ArrayList<Order>` instead of `HashMap`
    private final Map<String, Integer> cart = new HashMap<>(); // Stores itemName -> quantity

    public void addOrder(String itemName, Order order) {
        orders.add(order); // ✅ Allows duplicates naturally
    }

    public void removeOrder(String itemName) {
        orders.removeIf(order -> order.getName().equals(itemName));
    }

    public List<String> getCategoryDiscounts() {  // ✅ Uses `List<String>` Instead of HashMap
        return Arrays.asList("Cheap: 10%", "Moderate: 20%", "Expensive: 30%");
    }

    public void countDuplicateOrders() {
        cart.clear();
        for (Order order : orders) {
            cart.put(order.getName(), cart.getOrDefault(order.getName(), 0) + 1);
        }
    }

    public int calculateTotalDiscountedPrice() {
        int totalDiscountedPrice = 0;
        for (Order order : orders) {
            DiscountCategory category = DiscountCategory.getCategory(order.getPrice());
            int discountedPrice = (int) Math.round(order.getPrice() * (1 - category.getDiscount() / 100.0));
            totalDiscountedPrice += discountedPrice;
        }
        return totalDiscountedPrice;
    }

    public Map<String, Integer> showCart() {  
        return new HashMap<>(cart);
    }
}

class Solution {
    public static void main(String[] args) {
        IOrderManagement system = new OrderManagement();

        // Sample Input
        system.addOrder("Order-1", new Order("Order-1", 49));
        system.addOrder("Order-2", new Order("Order-2", 30));
        system.addOrder("Order-3", new Order("Order-3", 15));
        system.addOrder("Order-4", new Order("Order-4", 7));
        system.addOrder("Order-1", new Order("Order-1", 49)); // ✅ Duplicate item

        // Count duplicate items
        system.countDuplicateOrders();

        // Output
        System.out.println("Cart Contents: " + system.showCart());  
        System.out.println("Discounted Price: $" + system.calculateTotalDiscountedPrice());

        // Get category discounts
        System.out.println("Category Discounts: " + system.getCategoryDiscounts());

        // Removing an order
        system.removeOrder("Order-2");
        system.countDuplicateOrders(); // Recalculate duplicates
        System.out.println("Cart Contents after removal: " + system.showCart());
        System.out.println("Discounted Price after removal: $" + system.calculateTotalDiscountedPrice());
    }
}

📌 Key Fixes & Changes

1. ArrayList<Order> Instead of HashMap<String, Order>

  • Why? This allows duplicate orders to be stored naturally without needing a separate count.
  • Impact: addOrder() simply appends to orders without checking uniqueness.

2. Enum DiscountCategory Instead of HashMap<String, Integer>

  • Why? Provides a structured way to store & retrieve discount rates.
  • Impact: Cleaner code, easy to extend later.

3. getCategoryDiscounts() Returns a List<String> Instead of HashMap

  • Why? The discount values never change, so a static list is better.
  • Impact: Returns ["Cheap: 10%", "Moderate: 20%", "Expensive: 30%"] instead of a Map.

4. countDuplicateOrders() Counts Duplicates & Updates cart

  • Why? Since orders is a list (not a map), duplicates must be counted after adding orders.
  • Impact: Runs once before showCart() or calculateTotalDiscountedPrice().

📌 Expected Output

Cart Contents: {Order-1=2, Order-2=1, Order-3=1, Order-4=1}
Discounted Price: $117
Category Discounts: [Cheap: 10%, Moderate: 20%, Expensive: 30%]

Order Order-2 removed.

Cart Contents after removal: {Order-1=2, Order-3=1, Order-4=1}
Discounted Price after removal: $87

📌 Time Complexity Analysis

OperationTime ComplexityExplanation
Adding an order (addOrder())O(1)Appends to ArrayList (amortized O(1)).
Removing an order (removeOrder())O(N)Iterates over orders to find matches.
Counting duplicate orders (countDuplicateOrders())O(N)Iterates over orders to update cart.
Calculating discounted price (calculateTotalDiscountedPrice())O(N)Iterates over orders list.
Getting category discounts (getCategoryDiscounts())O(1)Returns a static list.
Showing the cart (showCart())O(N)Returns a copy of cart HashMap.

Overall efficiency remains O(N), which is optimal.


📌 Final Thoughts

FeaturePrevious (HashMap)New (ArrayList)
StorageUnique items onlyAllows duplicates naturally
Lookup TimeO(1)O(N) (must iterate)
Duplicate CountingNeeded separate functionHappens naturally
Discount StorageHashMap<String, Integer>Enum (Cleaner & Safer)

🔥 Final Recommendation

Use ArrayList<Order> when duplicates matter & insertion order is important.
Use Enum instead of HashMap for static category discounts.
This solution now meets all interview requirements perfectly! 🚀

Comments (3)