Make a list of product records and a list of order records, match the two lists by product id (join), and compute sales per product category.
Try solving it with query-style processing (C# LINQ, Java streams) instead of loops.
The first line gives the number of products p and the number of orders m.
The next p lines give products as "product_id category price", and the next m lines give orders as "product_id quantity", one per line.
If an order's product id is not in the product list, that order is left out of the totals.
On the first line, print the number of orders left out this way.
Then print "category units revenue" for each category that appears in the product list, one per line. Units is the sum of order quantities for products of that category, and revenue is the sum of price×quantity over those orders.
A category with no orders at all is also printed, as "category 0 0".
Print categories from the largest revenue down, and for equal revenue in dictionary order of the category name (by character code, so digits come before lowercase letters, and ab comes before abc).
Input
1 ≤ p ≤ 1,000, 1 ≤ m ≤ 5,000. Product ids and categories are 1 to 10 lowercase letters or digits, and product ids are distinct. 1 ≤ price ≤ 1,000,000, 1 ≤ quantity ≤ 1,000 (integers)
Output
first line: the number of orders left out, then "category units revenue" for each category
When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).
$ Ready
Open this on a computer to write and run code. On mobile you can read the problem and the solutions.
In other languagesShow solutions by language · 2 languages
This problem accepts only C# (LINQ) and Java (streams), the languages with query-style processing built in. They match two lists differently. C# has joins: orders.Join(products, o => o.ProductId, p => p.Id, ...) is an inner join that keeps only matched pairs, and products.GroupJoin(orders, ...) attaches a group of orders to each product, keeping products with no orders as empty groups (this is query syntax's join ... into). Java streams have no join, so you turn one side into a Map with Collectors.toMap(Product::id, Function.identity()) and match while walking the other. Four traps: ① With only an inner join, categories with no orders vanish entirely. In C#, start from the products as GroupJoin does; in Java, start from the list of categories in the products (distinct()) rather than the groupingBy Map, and attach with getOrDefault(c, List.of()). ② Unknown product ids: Java byId.get(id) returns null, so calling .price() on it throws NullPointerException, and C# Dictionary's dict[id] throws KeyNotFoundException. Join silently drops unmatched orders, so the count left out is orders.Count - matched.Count(). ③ Revenue reaches 5 trillion with 1,000,000 × 1,000 × 5,000 orders, so it must be long. Java mapToInt(...).sum() overflows silently, and C# LINQ Sum throws OverflowException when an int overflows. ④ Categories with no orders all tie at revenue 0, so sorting by name is essential. OrderByDescending and sorted are stable, so leaving out ThenBy/thenComparing keeps the order in which they appeared in the product list.
JavaMain.java · 72 lines
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.Comparator;import java.util.List;import java.util.Map;import java.util.function.Function;import java.util.stream.Collectors;record Product(String id, String category, long price) {}record Order(String productId, int qty) {}record Line(String category, int qty, long amount) {}record CategoryStat(String category, int units, long revenue) {}public class Main { public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String[] first = in.readLine().trim().split(" "); int p = Integer.parseInt(first[0]), m = Integer.parseInt(first[1]); List<Product> products = new ArrayList<>(); for (int i = 0; i < p; i++) { String[] s = in.readLine().trim().split(" "); products.add(new Product(s[0], s[1], Long.parseLong(s[2]))); } List<Order> orders = new ArrayList<>(); for (int i = 0; i < m; i++) { String[] s = in.readLine().trim().split(" "); orders.add(new Order(s[0], Integer.parseInt(s[1]))); } // 스트림에는 join이 없다: 한쪽을 id → 상품 Map으로 만들어 두고 맞춰 본다 Map<String, Product> byId = products.stream() .collect(Collectors.toMap(Product::id, Function.identity())); // 안쪽 조인: 짝이 되는 상품이 있는 주문만 List<Line> lines = orders.stream() .filter(o -> byId.containsKey(o.productId())) // 없으면 get이 null을 준다 .map(o -> { Product pr = byId.get(o.productId()); return new Line(pr.category(), o.qty(), pr.price() * o.qty()); }) .toList(); int unknown = orders.size() - lines.size(); // 종류별로 묶기. 주문이 없는 종류는 이 Map에 없다 Map<String, List<Line>> byCategory = lines.stream() .collect(Collectors.groupingBy(Line::category)); // 바깥 조인: 상품에 나온 모든 종류에서 출발해 묶음을 붙인다(없으면 빈 목록) List<CategoryStat> stats = products.stream() .map(Product::category) .distinct() .map(c -> { List<Line> ls = byCategory.getOrDefault(c, List.of()); return new CategoryStat(c, ls.stream().mapToInt(Line::qty).sum(), ls.stream().mapToLong(Line::amount).sum()); }) .sorted(Comparator.comparingLong(CategoryStat::revenue).reversed() .thenComparing(CategoryStat::category)) .toList(); StringBuilder out = new StringBuilder().append(unknown).append('\n'); for (CategoryStat s : stats) out.append(s.category()).append(' ').append(s.units()).append(' ').append(s.revenue()).append('\n'); System.out.print(out); }}
C#Main.cs · 46 lines
using System;using System.Collections.Generic;using System.Linq;using System.Text;record Product(string Id, string Category, long Price);record Order(string ProductId, int Qty);class Program{ static void Main() { string[] first = Console.ReadLine()!.Trim().Split(' '); int p = int.Parse(first[0]), m = int.Parse(first[1]); var products = new List<Product>(); for (int i = 0; i < p; i++) { string[] s = Console.ReadLine()!.Trim().Split(' '); products.Add(new Product(s[0], s[1], long.Parse(s[2]))); } var orders = new List<Order>(); for (int i = 0; i < m; i++) { string[] s = Console.ReadLine()!.Trim().Split(' '); orders.Add(new Order(s[0], int.Parse(s[1]))); } // 안쪽 조인(Join): 짝이 되는 상품이 없는 주문은 빠진다 var matched = orders.Join(products, o => o.ProductId, pr => pr.Id, (o, pr) => new { pr.Category, o.Qty, Amount = pr.Price * o.Qty }); int unknown = orders.Count - matched.Count(); // 묶음 조인(GroupJoin): 상품마다 그 상품의 주문 묶음. 주문이 없는 상품도 빈 묶음으로 남는다 var stats = products .GroupJoin(orders, pr => pr.Id, o => o.ProductId, (pr, os) => new { pr.Category, Units = os.Sum(o => o.Qty), Revenue = os.Sum(o => pr.Price * o.Qty) }) .GroupBy(x => x.Category) .Select(g => new { Category = g.Key, Units = g.Sum(x => x.Units), Revenue = g.Sum(x => x.Revenue) }) .OrderByDescending(s => s.Revenue) .ThenBy(s => s.Category, StringComparer.Ordinal); var sb = new StringBuilder().Append(unknown).Append('\n'); foreach (var s in stats) sb.Append($"{s.Category} {s.Units} {s.Revenue}\n"); Console.Write(sb); }}