게임 기록을 레코드(record)로 만들고, 반복문 대신 질의식 처리(C# LINQ, Java 스트림)로 묶고, 셈하고, 정렬하라.
첫 줄에 기록 수 n과 k가, 다음 n줄에 기록이 "판 선수 점수"로 하나씩 주어진다.
한 선수가 같은 판을 여러 번 했을 수 있다. 판마다 선수의 점수는 그 판에서 얻은 가장 높은 점수 하나로 친다.
판마다 선수를 점수가 높은 순으로, 점수가 같으면 이름의 코드 순서(ASCII, 대문자가 소문자보다 앞)로 늘어놓는다.
첫 줄에 판의 수를 출력하라.
이어서 판 이름의 코드 순서대로 판마다 한 줄에 "판 선수수 이름:점수 ..."를 출력하라. 선수수는 그 판을 한 서로 다른 선수의 수이고, 그 뒤에 앞에서부터 k명을 빈칸으로 띄워 적는다.
선수가 k명보다 적으면 모두 적는다. 이름은 대소문자를 가려서 Ann과 ann은 서로 다른 선수다.
입력
1 ≤ n ≤ 5000, 1 ≤ k ≤ 10. 판 이름은 영어 소문자 1 ~ 8글자이고, 서로 다른 판은 100개 이하다. 선수 이름은 영어 대소문자 1 ~ 8글자. 0 ≤ 점수 ≤ 1,000,000,000(정수)
출력
판의 수, 그리고 판마다 한 줄
예시 1 · stdin
6 2
cave ann 50
sky Bob 7
cave bob 70
cave ann 90
sky adam 7
cave Ann 70
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 2개 언어 풀이
이 문제는 질의식 처리가 언어에 들어 있는 C#(LINQ)과 Java(스트림)만 받아요. 묶음 안에서 한 번 더 묶어야 해요. C#은 GroupBy(판) 안에서 다시 GroupBy(선수)와 Max를 쓰고, Java는 groupingBy(판, TreeMap::new, toMap(선수, 점수, Math::max))처럼 모으기(collector)를 겹쳐 써요. 앞에서 k개는 C# Take(k), Java limit(k)이고, k가 더 크면 있는 만큼만 줘요. 함정 다섯: ① 선수로 다시 묶지 않고 기록을 그대로 정렬하면 같은 선수가 순위에 여러 번 들어가요. ② Java groupingBy의 기본은 HashMap이라 판의 차례가 정해져 있지 않아요(TreeMap::new를 줘요). C# GroupBy는 처음 나온 차례라서 OrderBy(g => g.Key)가 따로 필요해요. ③ Java에서 comparingInt(Best::score).thenComparing(Best::player).reversed()처럼 reversed()를 끝에 붙이면 그때까지 만든 비교 전체가 뒤집혀 이름 순서도 거꾸로 돼요. comparingInt(Best::score).reversed().thenComparing(Best::player)처럼 점수 바로 뒤에 붙여요. ④ C#에서 OrderByDescending 뒤에 OrderBy를 또 쓰면 앞의 정렬을 버리고 처음부터 다시 정렬해요. 두 번째 기준은 ThenBy로 적어요. ⑤ C# OrderBy·ThenBy가 문자열을 비교하는 기본 방법은 문화권 규칙이라 adam이 Bob보다 앞에 와요. 이 문제는 코드 순서(대문자가 먼저)라서 StringComparer.Ordinal을 줘야 해요. Java String.compareTo는 처음부터 코드 순서예요.
JavaMain.java · 44 줄
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.TreeMap;import java.util.stream.Collectors;record Play(String stage, String player, int score) {}record Best(String player, int score) {}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]), k = Integer.parseInt(first[1]); List<Play> plays = new ArrayList<>(); for (int i = 0; i < n; i++) { String[] p = in.readLine().trim().split(" "); plays.add(new Play(p[0], p[1], Integer.parseInt(p[2]))); } // 판으로 묶고(TreeMap: 판 이름 순서) → 판 안에서 선수마다 가장 높은 점수(toMap + Math::max) Map<String, Map<String, Integer>> best = plays.stream() .collect(Collectors.groupingBy(Play::stage, TreeMap::new, Collectors.toMap(Play::player, Play::score, Math::max))); StringBuilder out = new StringBuilder().append(best.size()).append('\n'); best.forEach((stage, players) -> { String top = players.entrySet().stream() .map(e -> new Best(e.getKey(), e.getValue())) .sorted(Comparator.comparingInt(Best::score).reversed() // 점수만 거꾸로 .thenComparing(Best::player)) // 이름은 그대로 .limit(k) .map(b -> b.player() + ":" + b.score()) .collect(Collectors.joining(" ")); out.append(stage).append(' ').append(players.size()).append(' ').append(top).append('\n'); }); System.out.print(out); }}
C#Main.cs · 42 줄
using System;using System.Collections.Generic;using System.Linq;using System.Text;record Play(string Stage, string Player, int Score);class Program{ static void Main() { string[] first = Console.ReadLine()!.Trim().Split(' '); int n = int.Parse(first[0]), k = int.Parse(first[1]); var plays = new List<Play>(); for (int i = 0; i < n; i++) { string[] p = Console.ReadLine()!.Trim().Split(' '); plays.Add(new Play(p[0], p[1], int.Parse(p[2]))); } // 판으로 묶고 → 판 안에서 다시 선수로 묶어 가장 높은 점수 → 정렬해서 k명 var stages = plays .GroupBy(r => r.Stage) .OrderBy(g => g.Key, StringComparer.Ordinal) // 문화권 규칙이 아니라 코드 순서로 .Select(g => { var ranked = g .GroupBy(r => r.Player) .Select(pg => (Player: pg.Key, Best: pg.Max(r => r.Score))) .OrderByDescending(x => x.Best) .ThenBy(x => x.Player, StringComparer.Ordinal) .ToList(); return (Stage: g.Key, Players: ranked.Count, Top: ranked.Take(k).Select(x => $"{x.Player}:{x.Best}")); }) .ToList(); var sb = new StringBuilder().Append(stages.Count).Append('\n'); foreach (var s in stages) sb.Append(s.Stage).Append(' ').Append(s.Players).Append(' ').Append(string.Join(" ", s.Top)).Append('\n'); Console.Write(sb); }}