import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
class Main {
public static void main(String[] args) {
List<Item> items = Arrays.asList(
new Item("Laptop", 1200.0), // Expensive
new Item("Mouse", 25.0), // Cheap
new Item("Keyboard", 75.0), // Moderate
new Item("Mouse", 30.0), // Cheap
new Item("Laptop", 1100.0), // Expensive
new Item("Monitor", 300.0) // Expensive
);
InventoryProcessor inventoryProcessor = new InventoryProcessorImpl();
System.out.println("countByCategory: " + inventoryProcessor.countByCategory(items));
var discountsByCategory = inventoryProcessor.calculateDiscountsByCategory(items);
inventoryProcessor.calculateDiscountsByCategory(items).forEach((k, v) -> System.out.println(k + ": " + String.format("%.2f", v)));
inventoryProcessor.getPricesByName(items).forEach((k, v) -> System.out.println(k + ": " + v.stream().map(value -> String.format("%.2f", value)).toList()));
}
}
class Item {
private String name;
private double price;
public Item(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() { return name; }
public double getPrice() { return price; }
}
interface InventoryProcessor {
/**
* Returns a map of category -> count of items in that category
* Categories: Cheap (< 50), Moderate (50-200), Expensive (> 200)
* Map must be sorted by category name (Cheap, Expensive, Moderate)
*/
Map<String, Integer> countByCategory(List<Item> items);
/**
* Returns a map of category -> total discounted amount for that category
* Discount rates: Cheap: 8%, Moderate: 12%, Expensive: 15%
* Values must be rounded to 2 decimal places
* Map must be sorted by category name
*/
Map<String, Double> calculateDiscountsByCategory(List<Item> items);
/**
* Returns a map of product name -> list of prices for that product
* Map must be sorted by product name alphabetically
* Prices in the list should be in their original order from input
*/
Map<String, List<Double>> getPricesByName(List<Item> items);
}
class InventoryProcessorImpl implements InventoryProcessor {
@Override
public Map<String, Integer> countByCategory(List<Item> items) {
if (items == null || items.isEmpty()) {
return new TreeMap<>();
}
return items.stream()
.map(Item::getPrice)
.collect(Collectors.groupingBy(this::getCategory, TreeMap::new, Collectors.summingInt(n -> 1)));
}
@Override
public Map<String, Double> calculateDiscountsByCategory(List<Item> items) {
if (items == null || items.isEmpty()) {
return new TreeMap<>();
}
Map<String, Double> totalDiscountsPerCategory = items.stream()
.collect(Collectors.groupingBy(item -> this.getCategory(item.getPrice()), TreeMap::new, Collectors.summingDouble(item -> item.getPrice())));
return totalDiscountsPerCategory.entrySet().stream()
.collect(Collectors.groupingBy(Map.Entry::getKey, TreeMap::new, Collectors.summingDouble(entry -> (entry.getValue() * this.getDiscount(entry.getKey()) * 100.0) / 100.0)));
}
@Override
public Map<String, List<Double>> getPricesByName(List<Item> items) {
if (items == null || items.isEmpty()) {
return new TreeMap<>();
}
return items.stream()
.collect(Collectors.groupingBy(Item::getName, Collectors.mapping(item -> item.getPrice(), Collectors.toList())));
}
private String getCategory(double price) {
if (price < 20) {
return "Cheap";
} else if (price >= 20 && price <= 100) {
return "Moderate";
}
return "Expensive";
}
private double getDiscount(String category) {
if ("Cheap".equals(category)) {
return 0.08;
} else if ("Moderate".equals(category)) {
return 0.12;
}
return 0.15;
}
}