{ }codelper
query pipelines (LINQ, streams)lists of recordsP0082

Orders by city

Make the order as a record, and filter, group and aggregate with query-style processing (C# LINQ, Java streams) instead of loops.
The first line gives the number of orders n and a threshold T, and the next n lines give one order each as "city customer amount".
Keep only orders whose amount is at least T.
Group the remaining orders by city and print "city order_count total top_customer" for each city.
The top customer is the customer of that city's largest order; if several orders share the largest amount, it is the customer of the one that appears first in the input.
On the first line print the number of cities that have remaining orders (print just 0 if no order remains), then one line per city, from the largest total down, with equal totals in dictionary order of the city name.

Input
1 ≤ n ≤ 5000, 1 ≤ T ≤ 1,000,000,000, 1 ≤ amount ≤ 1,000,000,000 (integers).
City and customer names are 1 to 10 lowercase English letters
Output
the city count c on the first line, then c lines (a total can grow to 5 trillion)
Example 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
Input (stdin)

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 takes only C# (LINQ) and Java (streams), where query-style processing is part of the language.
The same job is C# Where → GroupBy → Select → OrderByDescending → ThenBy and Java filter → collect(groupingBy) → map → sorted.
There are three traps.
First, 5000 orders of 1 billion make 5 trillion, so add them as long.
Both are wrong with int, but differently: Java mapToInt(...).sum() / summingInt overflows silently with no exception and gives a nonsense number, while C# LINQ Sum checks for overflow even on int and throws OverflowException (a plain unchecked + in C# overflows silently too).
Second, the order the groups come out in.
C# GroupBy yields groups in first-appearance order, but Java groupingBy uses a HashMap with no defined order (pass TreeMap::new for name order).
Either way you must write "equal totals by name" yourself with ThenBy(s => s.City) / thenComparing(CityStat::city).
Third, "at least T" is >=.
For the top customer, C# MaxBy (.NET 6) and Java max(Comparator) both return the first of equal values, so they work as is.
A Java stream can be used only once, so put it in a list if you need to go over it twice.
Java record and C# record both give you fields, a constructor and equality in one line.

JavaMain.java · 45 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.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 lines
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);    }}