{ }codelper
EOFまで読む小数の出力空白の除去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));