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 行
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); }}