{ }codelper
질의식 처리(LINQ·스트림)자료 목록P0082

도시별 주문 집계

주문 기록을 레코드(record)로 만들고, 반복문 대신 질의식 처리(C# LINQ, Java 스트림)로 걸러 내고, 묶고, 셈하라.
첫 줄에 주문 수 n과 기준 금액 T, 다음 n줄에 주문이 "도시 손님 금액"으로 하나씩 주어진다.
금액이 T 이상인 주문만 남긴다.
남은 주문을 도시별로 묶어, 도시마다 "도시 주문수 합계 큰손"을 출력한다.
큰손은 그 도시에서 금액이 가장 큰 주문을 한 손님이고, 가장 큰 금액이 여럿이면 입력에서 먼저 나온 주문의 손님이다.
첫 줄에 남은 주문이 있는 도시의 수를 출력하고(남은 주문이 없으면 0만 출력), 이어서 도시마다 한 줄씩 합계가 큰 도시부터, 합계가 같으면 도시 이름의 사전 순으로 출력하라.

입력
1 ≤ n ≤ 5000, 1 ≤ T ≤ 1,000,000,000, 1 ≤ 금액 ≤ 1,000,000,000(정수).
도시와 손님 이름은 영어 소문자 1 ~ 10글자
출력
첫 줄에 도시 수 c, 이어서 c줄(합계는 최대 5조까지 커진다)
예시 1 · stdin
7 10
seoul mina 30
busan jun 9
seoul ari 50
daegu seo 80
busan hana 10
seoul bo 50
busan kim 70
stdout
3
seoul 3 130 ari
busan 2 80 kim
daegu 1 80 seo
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 2개 언어 풀이

이 문제는 질의식 처리가 언어에 들어 있는 C#(LINQ)과 Java(스트림)만 받아요.
같은 일을 C# Where → GroupBy → Select → OrderByDescending → ThenBy, Java filter → collect(groupingBy) → map → sorted로 써요.
함정이 셋 있어요.
첫째, 합계는 10억짜리 5000건이면 5조라서 long으로 더해야 해요.
둘 다 int면 틀리는데 모양이 달라요: Java mapToInt(...).sum()·summingInt는 예외 없이 조용히 넘쳐 엉뚱한 수가 나오고, C# LINQ Sum은 int에서도 넘침을 검사해 OverflowException을 던져요(checked가 아닌 보통 +는 C#도 조용히 넘쳐요).
둘째, 묶음이 나오는 차례예요.
C# GroupBy는 처음 나온 차례대로 묶음을 내지만 Java groupingBy는 HashMap이라 차례가 정해져 있지 않아요(TreeMap::new를 주면 이름 순).
어느 쪽이든 "합계가 같으면 이름 순"을 ThenBy(s => s.City)·thenComparing(CityStat::city)로 직접 적어야 해요.
셋째, "T 이상"은 >=예요.
큰손은 C# MaxBy(.NET 6), Java max(Comparator)가 모두 같은 값 가운데 먼저 나온 것을 돌려줘서 그대로 쓸 수 있어요.
Java 스트림은 한 번만 쓸 수 있으니 두 번 돌려면 목록에 담아 두세요.
Java record와 C# record는 둘 다 필드·생성자·같음 비교를 한 줄로 만들어 줘요.

JavaMain.java · 45 줄
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.stream.Collectors; record Order(String city, String customer, long amount) {} record CityStat(String city, long count, long total, String top) {} 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 n = Integer.parseInt(first[0]);        long t = Long.parseLong(first[1]);        List<Order> orders = new ArrayList<>();        for (int i = 0; i < n; i++) {            String[] p = in.readLine().trim().split(" ");            orders.add(new Order(p[0], p[1], Long.parseLong(p[2])));        }         // 걸러서(filter) → 도시로 묶고(groupingBy) → 묶음마다 셈하기        Map<String, List<Order>> byCity = orders.stream()            .filter(o -> o.amount() >= t)            .collect(Collectors.groupingBy(Order::city)); // HashMap: 차례가 정해져 있지 않다         List<CityStat> stats = byCity.entrySet().stream()            .map(e -> new CityStat(                e.getKey(),                e.getValue().size(),                e.getValue().stream().mapToLong(Order::amount).sum(), // mapToInt면 21억에서 넘친다                e.getValue().stream().max(Comparator.comparingLong(Order::amount)).get().customer()))            .sorted(Comparator.comparingLong(CityStat::total).reversed().thenComparing(CityStat::city))            .toList();         StringBuilder out = new StringBuilder().append(stats.size()).append('\n');        for (CityStat s : stats)            out.append(s.city()).append(' ').append(s.count()).append(' ').append(s.total()).append(' ').append(s.top()).append('\n');        System.out.print(out);    }}
C#Main.cs · 41 줄
using System;using System.Collections.Generic;using System.Linq;using System.Text; record Order(string City, string Customer, long Amount); class Program{    static void Main()    {        string[] first = Console.ReadLine().Trim().Split(' ');        int n = int.Parse(first[0]);        long t = long.Parse(first[1]);        var orders = new List<Order>();        for (int i = 0; i < n; i++)        {            string[] p = Console.ReadLine().Trim().Split(' ');            orders.Add(new Order(p[0], p[1], long.Parse(p[2])));        }         // 걸러서(Where) → 도시로 묶고(GroupBy) → 묶음마다 셈하기(Select) → 정렬        var stats = orders            .Where(o => o.Amount >= t)            .GroupBy(o => o.City) // 처음 나온 차례로 묶음이 나온다            .Select(g => new            {                City = g.Key,                Count = g.Count(),                Total = g.Sum(o => o.Amount), // long이라 넘치지 않는다                Top = g.MaxBy(o => o.Amount)!.Customer, // 같으면 먼저 나온 것            })            .OrderByDescending(s => s.Total)            .ThenBy(s => s.City, StringComparer.Ordinal)            .ToList();         var sb = new StringBuilder().Append(stats.Count).Append('\n');        foreach (var s in stats) sb.Append($"{s.City} {s.Count} {s.Total} {s.Top}\n");        Console.Write(sb);    }}