{ }codelper
读到输入结束输出小数去除空白P0102

销售记录合计

销售记录每行一条,一直给到输入结束。
一条记录是商品名和金额,两者之间用一个以上的空白(空格或制表符)分隔。
行首和行尾也可能有空白。
空行或只有空白的行不是记录,跳过。
空行之后也可能还有记录。
对每个商品输出一行 "名字 条数 合计",按该商品第一次出现的顺序输出。
最后一行输出 "TOTAL 总条数 总合计"。
所有合计都精确写到小数点后两位(12.5 写成 12.50,7 写成 7.00)。
如果一条记录都没有,只输出 "TOTAL 0 0.00"。

输入
记录 0 到 10,000 行,每行不含换行符不超过 100 个字符,不同名字不超过 1,000 个。
名字为 1 到 12 个小写英文字母。
金额在 0 到 10,000 之间(含),像 "7"、"7.5"、"0.05" 那样没有小数部分或有 1 到 2 位小数
输出
每个商品一行,然后是 TOTAL 一行
样例 1 · stdin
mina 12.5
  jun 3
mina   0.05

jun 7.25  
stdout
mina 2 12.55
jun 2 10.25
TOTAL 4 22.80
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

各语言表示输入结束的方式不同。
Python for line in sys.stdin,Java readLine() 返回 null,C# Console.ReadLine() 返回 null,C fgets 返回 NULL,C++ getline 为假,JS·TS 用 readFileSync(0) 一次读完再分行。
Craykon 中 控制台.读行() 为 空 就是结束。
空行("")不是输入结束,在空行停下就会漏掉后面的记录。
分割时,JS line.split(" ") 遇到两个空格会产生空片段 "",而 Number("") 不报错地得到 0,于是悄悄出错。
请在 trim() 之后用 split(/\s+/)。
Python split()、C# Split((char[])null, RemoveEmptyEntries)、C++ >>、C sscanf、Craykon 分割() 无论空白连续几个都一次分开。
保留两位小数用 Python f"{x:.2f}"、JS·TS x.toFixed(2)、C·C++ printf("%.2f")。
不加格式会输出 12.5 或 0.30000000000000004(0.1 + 0.2)。
Java String.format 和 C# ToString("F2") 跟随电脑的区域设置,德语设置下会输出 12,50,所以要传入 Locale.ROOT 和 CultureInfo.InvariantCulture。
在 C 中用 float 累加,有效数字只有约 7 位,合计接近 1 亿时就会出错,请用 double。
Craykon 用 字符.保留小数(合计, 2) 输出,名字的顺序由 字典() 的 键列表 按插入顺序保持。

Pythonmain.py · 19 行
import sys totals = {}  # 이름 → [건수, 합계]. dict는 처음 넣은 차례를 지킨다all_count, all_sum = 0, 0.0for line in sys.stdin:  # 입력이 끝날 때까지    line = line.strip()    if not line:  # 빈 줄은 건너뛴다(입력 끝이 아님)        continue    name, amount = line.split()    amount = float(amount)    if name not in totals:        totals[name] = [0, 0.0]    totals[name][0] += 1    totals[name][1] += amount    all_count += 1    all_sum += amountfor name, (count, total) in totals.items():    print(f"{name} {count} {total:.2f}")print(f"TOTAL {all_count} {all_sum:.2f}")
JavaScriptmain.js · 20 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const totals = new Map(); // 이름 → { count, sum }, 처음 넣은 차례let allCount = 0;let allSum = 0;for (const raw of lines) {  const line = raw.trim();  if (line === "") continue; // 빈 줄은 건너뛴다  const [name, amount] = line.split(/\s+/); // 빈칸이 여러 개여도 한 번에  const x = Number(amount);  if (!totals.has(name)) totals.set(name, { count: 0, sum: 0 });  const t = totals.get(name);  t.count++;  t.sum += x;  allCount++;  allSum += x;}const out = [];for (const [name, t] of totals) out.push(`${name} ${t.count} ${t.sum.toFixed(2)}`);out.push(`TOTAL ${allCount} ${allSum.toFixed(2)}`);console.log(out.join("\n"));
TypeScriptmain.ts · 22 行
import { readFileSync } from "node:fs";interface Tally { count: number; sum: number }const lines: string[] = readFileSync(0, "utf8").split("\n");const totals = new Map<string, Tally>(); // 처음 넣은 차례를 지킨다let allCount = 0;let allSum = 0;for (const raw of lines) {  const line: string = raw.trim();  if (line === "") continue; // 빈 줄은 건너뛴다  const [name, amount] = line.split(/\s+/);  const x: number = Number(amount);  const t: Tally = totals.get(name) ?? { count: 0, sum: 0 };  t.count++;  t.sum += x;  totals.set(name, t);  allCount++;  allSum += x;}const out: string[] = [];for (const [name, t] of totals) out.push(`${name} ${t.count} ${t.sum.toFixed(2)}`);out.push(`TOTAL ${allCount} ${allSum.toFixed(2)}`);console.log(out.join("\n"));
JavaMain.java · 33 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.LinkedHashMap;import java.util.Locale;import java.util.Map; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        Map<String, Integer> counts = new LinkedHashMap<>(); // 처음 넣은 차례를 지킨다        Map<String, Double> sums = new LinkedHashMap<>();        int allCount = 0;        double allSum = 0;        String line;        while ((line = in.readLine()) != null) { // null이면 입력 끝            line = line.trim();            if (line.isEmpty()) continue;            String[] p = line.split("\\s+");            double x = Double.parseDouble(p[1]);            counts.merge(p[0], 1, Integer::sum);            sums.merge(p[0], x, Double::sum);            allCount++;            allSum += x;        }        StringBuilder out = new StringBuilder();        // Locale.ROOT: 소수점이 쉼표인 지역 설정에서도 12.50으로        for (String name : counts.keySet())            out.append(String.format(Locale.ROOT, "%s %d %.2f%n", name, counts.get(name), sums.get(name)));        out.append(String.format(Locale.ROOT, "TOTAL %d %.2f%n", allCount, allSum));        System.out.print(out);    }}
C#Main.cs · 40 行
using System;using System.Collections.Generic;using System.Globalization;using System.Text; class Program{    static void Main()    {        var inv = CultureInfo.InvariantCulture; // 소수점이 늘 '.'        var names = new List<string>(); // Dictionary는 차례를 약속하지 않아서 따로 둔다        var counts = new Dictionary<string, int>();        var sums = new Dictionary<string, double>();        int allCount = 0;        double allSum = 0;        string line;        while ((line = Console.ReadLine()) != null)        {            line = line.Trim();            if (line.Length == 0) continue;            string[] p = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);            double x = double.Parse(p[1], inv);            if (!counts.ContainsKey(p[0]))            {                names.Add(p[0]);                counts[p[0]] = 0;                sums[p[0]] = 0;            }            counts[p[0]]++;            sums[p[0]] += x;            allCount++;            allSum += x;        }        var sb = new StringBuilder();        foreach (string name in names)            sb.Append(name).Append(' ').Append(counts[name]).Append(' ').Append(sums[name].ToString("F2", inv)).Append('\n');        sb.Append("TOTAL ").Append(allCount).Append(' ').Append(allSum.ToString("F2", inv)).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 39 行
#include <cstdio>#include <iostream>#include <sstream>#include <string>#include <unordered_map>#include <vector> int main() {    std::vector<std::string> names;              // 처음 나온 차례    std::unordered_map<std::string, int> at;     // 이름 → names의 자리    std::vector<int> counts;    std::vector<double> sums;    int allCount = 0;    double allSum = 0;    std::string line;    while (std::getline(std::cin, line)) { // 실패하면 입력 끝        std::istringstream ss(line);        // >>는 앞뒤·사이 빈칸을 모두 건너뛴다        std::string name;        double x;        if (!(ss >> name >> x)) continue;   // 빈 줄        auto it = at.find(name);        int i;        if (it == at.end()) {            i = (int)names.size();            at[name] = i;            names.push_back(name);            counts.push_back(0);            sums.push_back(0);        } else {            i = it->second;        }        counts[i]++;        sums[i] += x;        allCount++;        allSum += x;    }    for (std::size_t i = 0; i < names.size(); i++) std::printf("%s %d %.2f\n", names[i].c_str(), counts[i], sums[i]);    std::printf("TOTAL %d %.2f\n", allCount, allSum);}
Cmain.c · 29 行
#include <stdio.h>#include <string.h> #define MAXN 1000 static char names[MAXN][13];static int counts[MAXN];static double sums[MAXN]; /* float는 유효 숫자가 7자리뿐이라 합이 커지면 틀린다 */static int k = 0; int main(void) {    char line[256], name[16];    double x;    int all_count = 0;    double all_sum = 0;    while (fgets(line, sizeof line, stdin)) { /* NULL이면 입력 끝 */        if (sscanf(line, "%12s %lf", name, &x) != 2) continue; /* 빈 줄 */        int i = 0;        while (i < k && strcmp(names[i], name) != 0) i++;        if (i == k) strcpy(names[k++], name);        counts[i]++;        sums[i] += x;        all_count++;        all_sum += x;    }    for (int i = 0; i < k; i++) printf("%s %d %.2f\n", names[i], counts[i], sums[i]);    printf("TOTAL %d %.2f\n", all_count, all_sum);    return 0;}
Craykonmain.cray · 30 行
counts = 字典();sums = 字典();allCount = 0;allSum = 0;line = 控制台.读行();当 (line != 空){    line = line.去空白();    // 빈 줄은 건너뛴다(입력 끝은 빈값)    如果 (line != "")    {        p = line.分割();        x = p[1].转数字();        如果 (!counts.包含(p[0]))        {            counts[p[0]] = 0;            sums[p[0]] = 0;        }        counts[p[0]] += 1;        sums[p[0]] += x;        allCount += 1;        allSum += x;    }    line = 控制台.读行();}遍历 (name 在 counts.键列表){    控制台.输出(name + " " + counts[name] + " " + 字符.保留小数(sums[name], 2));}控制台.输出("TOTAL " + allCount + " " + 字符.保留小数(allSum, 2));