Go 言語で「基礎プログラミング演習 I 〜100 本ノック中級編」を解いてみる-No.57「テスト集計」

はじめに

「基礎プログラミング演習 I 〜100 本ノック中級編」を解いてみます。

取り扱う問題は以下のサイトを引用させていただきました。

検証環境

$ uname -moi
x86_64 unknown GNU/Linux

$ head -n 2 /etc/os-release
PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"

$ go version | head -n 1
go version go1.16.3 linux/amd64

問題

No. 57 テスト集計

まず受験者数を入力させ、次に受験者数ごとに英語、数学、国語の点数をスペースで区切って入力させる(具体的な入力方法は下記の scanf の使い方の説明、および入力データの中身を見よ)。入力が終了したら、英語、数学、国語の平均点、および各受験生の合計点を計算して表示するプログラムを作成せよ。受験者数は 100 人までとする。なお、データの個数とデータはファイルからリダイレクトで入力させればよいので、入力のためのメッセージは不要である(実行例を参照すること)。

# 【実行例、データファイルは下のリンクから取得せよ】
$ ./knock57 < examSmall.data
平均点 英語:46, 数学:51, 国語:55
個人合計点
0: 141
1: 114
(途中省略)
8: 96
9: 188

$ ./knock57 < examMiddle.data
平均点 英語:55, 数学:53, 国語:54
個人合計点
0: 136
1: 64
(途中省略)
48: 265
49: 167

$ ./knock57 < examLarge.data
平均点 英語:52, 数学:51, 国語:51
個人合計点
0: 151
1: 241
(途中省略)
98: 107
99: 178

回答

knock57.go

package main

import (
    "fmt"
    "io"
    "log"
)

func main() {
    var eng, math, lang int

    // 一行目は不要
    var dummy int
    fmt.Scanln(&dummy)

    totalScoreOfEng := 0
    totalScoreOfMath := 0
    totalScoreOfLang := 0
    var eachTotalScore []int

    for true {
        _, err := fmt.Scanf("%d %d %d", &eng, &math, &lang)
        if err == io.EOF {
            break
        } else if err != nil {
            log.Fatal(err)
        }

        totalScoreOfEng += eng
        totalScoreOfMath += math
        totalScoreOfLang += lang

        eachTotalScore = append(eachTotalScore, eng+math+lang)
    }

    fmt.Printf(
        "平均点 英語:%d, 数学:%d, 国語:%d\n",
        totalScoreOfEng/len(eachTotalScore),
        totalScoreOfMath/len(eachTotalScore),
        totalScoreOfLang/len(eachTotalScore),
    )
    fmt.Println("個人合計点")
    for i, score := range eachTotalScore {
        fmt.Printf("%d: %d\n", i, score)
    }
}

実行

事前にデータファイルをダウンロードしておきます。

$ curl -O http://www.cc.kyoto-su.ac.jp/~mmina/bp1/examSmall.data
$ curl -O http://www.cc.kyoto-su.ac.jp/~mmina/bp1/examMiddle.data
$ curl -O http://www.cc.kyoto-su.ac.jp/~mmina/bp1/examLarge.data

一点だけ、事前にダウンロードしたデータファイルを加工しておきます。
(意図したものかどうかわかりませんが、各行末にスペースが入っていたり入っていなかったりして正常に読み込めないケースが発生していたため、一律除去しています。)

$ find . -type f -name '*.data' | xargs -n 1 sed -i 's/\s\+$//g'

最後に実行します。

$ go run . < examSmall.data
平均点 英語:46, 数学:51, 国語:55
個人合計点
0: 141
1: 114
2: 107
3: 145
4: 201
5: 145
6: 201
7: 197
8: 96
9: 188

$ go run . < examMiddle.data
平均点 英語:55, 数学:53, 国語:54
個人合計点
0: 136
1: 64
2: 144
3: 101
4: 160
5: 261
6: 197
7: 164
8: 143
9: 116
10: 154
(途中省略)
45: 114
46: 181
47: 132
48: 265
49: 167

$ go run . < examLarge.data
平均点 英語:52, 数学:51, 国語:51
個人合計点
0: 151
1: 241
2: 145
3: 146
4: 156
5: 118
6: 128
7: 97
8: 184
9: 249
10: 203
(途中省略)
95: 164
96: 289
97: 141
98: 107
99: 178

ひとこと

一行目を呼び飛ばす適切な方法がわからず強引に。

今回は標準入力を一行ずつ読み込みましたが、行を分割するために fmt.Scanf を使いました。

Posted by genzouw