{ }codelper
桁そろえ書式つき出力P0096

成績表を作る

一行目に学生の数 n が与えられ、続く n 行に「名前 国語 英語 数学」が一つずつ与えられる。
NAME、KOR、ENG、MATH、AVG の五列の表を出力せよ。
AVG は三つの点数の平均を小数第一位まで四捨五入した値である(275 / 3 → 91.7、171 / 3 → 57.0)。
- 列ごとの幅は、その列の見出しとその列に入る値のうち最も長いものの文字数である。
- 一行目は見出し、二行目は列ごとに幅の数だけの "-" を "-+-" でつないだ行、その後は学生ごとに一行(入力順)である。
- 見出し行と学生の行では、列の間に " | "(空白、縦棒、空白)を入れる。
NAME 列は左寄せ(後ろに空白)、その他の列は右寄せ(前に空白)である。
見出しも同じ規則に従う。

入力
1 ≤ n ≤ 20、名前は英字 1~15 文字、0 ≤ 各点数 ≤ 100
出力
n + 2 行の表
例 1 · stdin
3
Kim 90 85 100
Alexander 7 100 64
Bo 100 100 100
stdout
NAME      | KOR | ENG | MATH |   AVG
----------+-----+-----+------+------
Kim       |  90 |  85 |  100 |  91.7
Alexander |   7 | 100 |   64 |  57.0
Bo        | 100 | 100 |  100 | 100.0
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

まず列ごとの幅を(見出しも入れて)測り、それから揃えて書きます。
見出しを忘れると、名前がすべて短いとき NAME が列からはみ出します。
実行中に幅を決める方法は言語によって違います。
Python f"{s:<{w}}"・f"{s:>{w}}"、C printf("%-*s", w, s)・"%*s"(* の所に幅を渡す)、C++ std::left/std::right と std::setw(w)、Java String.format("%-" + w + "s", s)、JS・TS padEnd/padStart、C# PadRight/PadLeft(C# の {0,-5} は幅が定数でなければなりません)。
平均は / 3.0 のように実数で割る必要があります。
C・C++・Java・C# で (a + b + c) / 3 は整数の割り算なので、91.7 が 91 になります。
Craykon は 後埋め(幅)/前埋め(幅) で揃え、小数一桁は 文字.桁そろえ(合計 / 3, 1)、線は "-".繰り返し(w) と つなぐ("-+-") で作ります。

Pythonmain.py · 22 行
n = int(input())headers = ["NAME", "KOR", "ENG", "MATH", "AVG"]rows = []for _ in range(n):    name, *scores = input().split()    a, b, c = map(int, scores)    rows.append([name, str(a), str(b), str(c), f"{(a + b + c) / 3:.1f}"]) # 칸 너비 = 머리글과 그 칸 값들 가운데 가장 긴 것widths = [max(len(r[i]) for r in [headers] + rows) for i in range(5)]  def line(cells):    # 이름은 왼쪽 맞춤, 나머지는 오른쪽 맞춤    parts = [f"{cells[0]:<{widths[0]}}"] + [f"{cells[i]:>{widths[i]}}" for i in range(1, 5)]    return " | ".join(parts)  print(line(headers))print("-+-".join("-" * w for w in widths))for r in rows:    print(line(r))
JavaScriptmain.js · 15 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);const headers = ["NAME", "KOR", "ENG", "MATH", "AVG"];const rows = [];for (let i = 1; i <= n; i++) {  const [name, ...rest] = lines[i].trim().split(/\s+/);  const [a, b, c] = rest.map(Number);  rows.push([name, String(a), String(b), String(c), ((a + b + c) / 3).toFixed(1)]);}// 칸 너비 = 머리글과 그 칸 값들 가운데 가장 긴 것const widths = headers.map((_, i) => Math.max(...[headers, ...rows].map((r) => r[i].length)));// 이름은 왼쪽 맞춤(padEnd), 나머지는 오른쪽 맞춤(padStart)const line = (cells) => cells.map((s, i) => (i === 0 ? s.padEnd(widths[i]) : s.padStart(widths[i]))).join(" | ");const out = [line(headers), widths.map((w) => "-".repeat(w)).join("-+-"), ...rows.map(line)];console.log(out.join("\n"));
TypeScriptmain.ts · 16 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const n: number = Number(lines[0]);const headers: string[] = ["NAME", "KOR", "ENG", "MATH", "AVG"];const rows: string[][] = [];for (let i = 1; i <= n; i++) {  const [name, ...rest] = lines[i].trim().split(/\s+/);  const [a, b, c] = rest.map(Number);  rows.push([name, String(a), String(b), String(c), ((a + b + c) / 3).toFixed(1)]);}// 칸 너비 = 머리글과 그 칸 값들 가운데 가장 긴 것const widths: number[] = headers.map((_, i) => Math.max(...[headers, ...rows].map((r) => r[i].length)));// 이름은 왼쪽 맞춤(padEnd), 나머지는 오른쪽 맞춤(padStart)const line = (cells: string[]): string => cells.map((s, i) => (i === 0 ? s.padEnd(widths[i]) : s.padStart(widths[i]))).join(" | ");const out: string[] = [line(headers), widths.map((w) => "-".repeat(w)).join("-+-"), ...rows.map(line)];console.log(out.join("\n"));
JavaMain.java · 47 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;import java.util.Locale; public class Main {    static int[] widths = new int[5];     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(in.readLine().trim());        String[] headers = {"NAME", "KOR", "ENG", "MATH", "AVG"};        List<String[]> rows = new ArrayList<>();        rows.add(headers);        for (int i = 0; i < n; i++) {            String[] t = in.readLine().trim().split("\\s+");            int a = Integer.parseInt(t[1]), b = Integer.parseInt(t[2]), c = Integer.parseInt(t[3]);            // Locale.ROOT: 소수점이 쉼표인 지역 설정에서도 91.7로 찍게            String avg = String.format(Locale.ROOT, "%.1f", (a + b + c) / 3.0);            rows.add(new String[] {t[0], t[1], t[2], t[3], avg});        }        // 칸 너비 = 머리글과 그 칸 값들 가운데 가장 긴 것        for (String[] r : rows)            for (int i = 0; i < 5; i++) widths[i] = Math.max(widths[i], r[i].length());        StringBuilder out = new StringBuilder();        for (int k = 0; k < rows.size(); k++) {            out.append(line(rows.get(k))).append('\n');            if (k == 0) {                for (int i = 0; i < 5; i++) {                    if (i > 0) out.append("-+-");                    out.append("-".repeat(widths[i]));                }                out.append('\n');            }        }        System.out.print(out);    }     // 이름은 왼쪽 맞춤(%-Ns), 나머지는 오른쪽 맞춤(%Ns)    static String line(String[] cells) {        StringBuilder sb = new StringBuilder(String.format("%-" + widths[0] + "s", cells[0]));        for (int i = 1; i < 5; i++) sb.append(" | ").append(String.format("%" + widths[i] + "s", cells[i]));        return sb.toString();    }}
C#Main.cs · 30 行
using System;using System.Collections.Generic;using System.Globalization;using System.Linq; class Program{    static void Main()    {        int n = int.Parse(Console.ReadLine());        string[] headers = { "NAME", "KOR", "ENG", "MATH", "AVG" };        var rows = new List<string[]> { headers };        for (int i = 0; i < n; i++)        {            string[] t = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);            int a = int.Parse(t[1]), b = int.Parse(t[2]), c = int.Parse(t[3]);            // InvariantCulture: 소수점이 쉼표인 문화권 설정에서도 91.7로 찍게            string avg = ((a + b + c) / 3.0).ToString("F1", CultureInfo.InvariantCulture);            rows.Add(new[] { t[0], t[1], t[2], t[3], avg });        }        // 칸 너비 = 머리글과 그 칸 값들 가운데 가장 긴 것        int[] widths = Enumerable.Range(0, 5).Select(i => rows.Max(r => r[i].Length)).ToArray();        // 이름은 왼쪽 맞춤(PadRight), 나머지는 오른쪽 맞춤(PadLeft)        string Line(string[] cells) =>            string.Join(" | ", cells.Select((s, i) => i == 0 ? s.PadRight(widths[i]) : s.PadLeft(widths[i])));        Console.WriteLine(Line(headers));        Console.WriteLine(string.Join("-+-", widths.Select(w => new string('-', w))));        foreach (var r in rows.Skip(1)) Console.WriteLine(Line(r));    }}
C++main.cpp · 34 行
#include <algorithm>#include <iomanip>#include <iostream>#include <sstream>#include <string>#include <vector> int main() {    int n;    std::cin >> n;    std::vector<std::vector<std::string>> rows = {{"NAME", "KOR", "ENG", "MATH", "AVG"}};    for (int i = 0; i < n; i++) {        std::string name;        int a, b, c;        std::cin >> name >> a >> b >> c;        std::ostringstream avg;        avg << std::fixed << std::setprecision(1) << (a + b + c) / 3.0;        rows.push_back({name, std::to_string(a), std::to_string(b), std::to_string(c), avg.str()});    }    // 칸 너비 = 머리글과 그 칸 값들 가운데 가장 긴 것    std::vector<std::size_t> widths(5, 0);    for (const auto& r : rows)        for (int i = 0; i < 5; i++) widths[i] = std::max(widths[i], r[i].size());    auto print_row = [&](const std::vector<std::string>& r) {        // 이름은 왼쪽 맞춤(std::left), 나머지는 오른쪽 맞춤(std::right)        std::cout << std::left << std::setw(widths[0]) << r[0];        for (int i = 1; i < 5; i++) std::cout << " | " << std::right << std::setw(widths[i]) << r[i];        std::cout << '\n';    };    print_row(rows[0]);    for (int i = 0; i < 5; i++) std::cout << (i > 0 ? "-+-" : "") << std::string(widths[i], '-');    std::cout << '\n';    for (std::size_t k = 1; k < rows.size(); k++) print_row(rows[k]);}
Cmain.c · 40 行
#include <stdio.h>#include <string.h> static char cells[21][5][16];static int widths[5]; // 이름은 왼쪽 맞춤(%-*s), 나머지는 오른쪽 맞춤(%*s) — *에 너비를 넘긴다static void print_row(int r) {    printf("%-*s", widths[0], cells[r][0]);    for (int i = 1; i < 5; i++) printf(" | %*s", widths[i], cells[r][i]);    printf("\n");} int main(void) {    int n, a, b, c;    const char *headers[5] = {"NAME", "KOR", "ENG", "MATH", "AVG"};    for (int i = 0; i < 5; i++) strcpy(cells[0][i], headers[i]);    scanf("%d", &n);    for (int r = 1; r <= n; r++) {        scanf("%15s %d %d %d", cells[r][0], &a, &b, &c);        sprintf(cells[r][1], "%d", a);        sprintf(cells[r][2], "%d", b);        sprintf(cells[r][3], "%d", c);        sprintf(cells[r][4], "%.1f", (a + b + c) / 3.0);    }    // 칸 너비 = 머리글과 그 칸 값들 가운데 가장 긴 것    for (int r = 0; r <= n; r++)        for (int i = 0; i < 5; i++) {            int len = strlen(cells[r][i]);            if (len > widths[i]) widths[i] = len;        }    print_row(0);    for (int i = 0; i < 5; i++) {        if (i > 0) printf("-+-");        for (int k = 0; k < widths[i]; k++) putchar('-');    }    printf("\n");    for (int r = 1; r <= n; r++) print_row(r);    return 0;}
Craykonmain.cray · 39 行
// 이름은 왼쪽 맞춤(뒤채우기), 나머지는 오른쪽 맞춤(앞채우기)줄만들기(cells){    line = cells[0].後埋め(widths[0]);    繰り返す (i = 1; i < 5; i++)    {        line += " | " + cells[i].前埋め(widths[i]);    }    返す line;} n = コンソール.行読み().数に();rows = [["NAME", "KOR", "ENG", "MATH", "AVG"]];繰り返す (r = 0; r < n; r++){    t = コンソール.行読み().分ける();    합 = t[1].数に() + t[2].数に() + t[3].数に();    rows.追加([t[0], t[1], t[2], t[3], 文字.桁そろえ(합 / 3, 1)]);}// 칸 너비 = 머리글과 그 칸 값들 가운데 가장 긴 것widths = 新リスト(5, 0);それぞれ (row の中 rows){    繰り返す (i = 0; i < 5; i++)    {        widths[i] = 数学.大きい方(widths[i], row[i].長さ);    }}dashes = [];それぞれ (w の中 widths){    dashes.追加("-".繰り返し(w));}コンソール.書く(줄만들기(rows[0]));コンソール.書く(dashes.つなぐ("-+-"));繰り返す (r = 1; r < rows.個数; r++){    コンソール.書く(줄만들기(rows[r]));}