2016年度 発展プログラミング演習 最終課題
概要
目標
とある講義の,小テスト,定期試験,課題のデータが与えられます. これらの情報をもとに,次のことを行ってください.
-
簡易版の最終成績を算出してください。
- 簡易版の最終成績は、定期試験の点数です。
- その点数を元に、秀、優、良、可、不可、K(未受験)のグレードを判定してください。
- IDと最終成績(点数)とグレードをコンマ区切りで出力してください。1行に1名の学生の成績を出力してください。
-
最終成績を出力してください.
- 最終成績の算出方法は、定期試験が70%、課題が25%、小テストの受験率が5% です。
- 小数点以下は切り上げてください。
- その点数を元に、秀、優、良、可、不可、K(未受験)のグレードを判定してください。
- IDと最終成績(点数)とグレードをコンマ区切りで出力してください。1行に1名の学生の成績を出力してください。
- 全体の統計情報を算出してください.
- 最終成績全体の平均点,最高点,最低点を算出してください.
-
最終成績の分布を算出してください.
- 各グレード(秀、優、良、可、不可、K)に属している人数を算出してください。
- 2までの出力を行った後、上記の統計情報を出力してください。
- 以下の特別ルールを適用して,最終成績を算出してください.
- 定期試験の素点が80点以上であれば、最終成績をその点数にする。
- ただし、前に述べた算出方法で出した点数の方が高得点であれば、その点数を最終成績とします。
- 小数点以下は切り上げてください。
- ここで得られた点数を元に、秀、優、良、可、不可、K(未受験)、 ※(出席に数不足)のグレードを判定してください。
- ※(出席に数不足)は、点数が60点未満かつ、小テスト受験回数が7日以下の学生に対してつけられます。
- IDと最終成績(点数)とグレードをコンマ区切りで出力してください。1行に1名の学生の成績を出力してください。
-
オプション解析を行ってください。
- 成績ファイルを
-record
オプションで受け取ってください。 - 出席ファイルを
-attendance
オプションで受け取ってください。 - 小テストファイルを
-miniexam
オプションで受け取ってください。 - 出力先を
-output
オプションで受け取ってください。 - それぞれ、指定されなければ、その点数は0として扱い、上記3, 4, 5の処理を行うようにしてください。
- 成績ファイルを
-
その他の統計情報を算出してください。
- 成績(定期試験、最終成績)の順位を算出してください。
- 単位取得率を算出してください。
- 秀、優、良、可、不可、K、※の割合を算出してください。
- 秀、優、良、可の単位取得者における割合を算出してください。
この課題に必要な内容
- 自分独自の型を定義できる.
- Listの使い方.
- 文字列同士の比較.
- Mapの使い方.
- コマンドライン引数の扱い方.
- File型の使い方.
- String型からInteger型への相互変換.
- 文字ストリームを使って,ファイルを読む.
- 例外機構.
- 文字ストリームを使って,ファイルを書く.
課題の進め方
この課題は大きく6つに分けられます.それぞれの課題で,
GradeChecker1.java
〜GradeChecker6.java
を作成します.
以下のことを念頭に課題を進めてください.
- 1から順に取り組んでください.
- 1でできた内容を踏まえて2に取り組んでください.
- 3以降も同様に前の番号の内容をすべて盛り込んで,当該番号に取り組んでください.
- プログラムを作成するとき,一つ前のプログラムをコピーして始めるのも良いでしょう.
- ただし,その場合,
main
メソッドの内容を修正するのを忘れないようにしてください. main
メソッドで,異なる型をnew
するバグはなかなか気付きません.
- ただし,その場合,
- 2. 最終成績を出力してください までが必須です. それ以降はチャレンジ問題です.
課題の提出方法
この課題は大きく6つに分けられます.
それぞれの課題で,GradeChecker1.java
〜GradeChecker6.java
を作成します.
また,指定はしていませんが,独自の型を作成する必要もあるでしょう.
それらすべてのソースファイルをzip圧縮してください.
zip圧縮したファイルの名前は,6桁の「学生証番号.zip」としてください.
データやクラスファイルは含める必要はありません.
提出期限は,2016年7月31日(日) 24:00です.
提出先はMoodleの【〆切 2016/7/31 24:00】最終課題です.
次のチェックリストを提出前に確認してください.
- 空のディレクトリを作成し,その中に必要なソースファイルをすべて入れた.
- その状態でコンパイルに成功した.
- すべてのソースファイルにコメントとして,自分の学生証番号,名前が書かれている.
課題のデータ
課題のデータは次からダウンロードしてください. なお,提出されたプログラムは以下のデータとは異なるデータを使って評価します. データの形式は同じですが,記載されているデータは異なります. そのため,しっかりとデータを読み,適切な分析を行うようにしてください. なお,多少(小数点以下第4位程度)の計算誤差は許容されます.
1. 簡易版の最終成績を算出してください。
1-A. 問題説明
プログラムの実行時に,引数に試験成績のcsvファイルが渡されます. csvファイルは,IDと点数が記載されています. その点数を読み,秀,優,良,可,不可,K(未受験)のグレードを判定してください. IDは番号順に並んでいますが,番号が飛んでいる場合があります. その場合は,飛んだ番号は未受験であるため,0点,Kと出力してください.
点数が60点未満が不可,60以上70点未満が可,70点以上80点未満が良,80点以上90点未満が優,
90点以上が秀です.K(未受験)はexam.csv
に掲載されていません.
IDが飛んだ時,その学生のグレードをKにしてください.
ファイル名は,GradeChecker1.java
としてください.
なお,入力ファイルの行数が増減した場合でも適切に処理が行えるようにしてください.
1-B. 実行例
$ cat exam.csv 1,70.05347594 3,86.09625668 4,85.02673797 5,56.14973262 ... 以下略 $ java GradeChecker1 exam.csv 1,70.053, 良 2,0.000, K 3,86.096, 優 4,85.027, 優 5,56.150, 不可 ... 以下略
出力例を左に示します. IDの昇順になるように出力してください. 「ID, 最終成績,グレード」をコンマ区切りで出力してください.
なお,左図からもわかるように,exam.csv
には,ID 2が抜けています.
そのため,2番目の学生は未受験であるため,出力では,2番の学生は0点でグレードがKになっています.
1-C. 参考資料
1-C-1. コンマ区切りの文字列を分割する
String item1 = "1,70.05347594"; // コンマ(,)で分割し,itemsに代入する. String[] items1 = item1.split(","); System.out.printf("%s,%s%n", items1[0], items1[1]); // 「1,70.05347594」が出力される. String item2 = "3,,,,,"; String[] items2 = item2.split(","); System.out.printf("%d%n", items2.length); // 「1」が出力される.
コンマで区切られた文字列を分割するには,String
型のsplit
メソッドを利用します.
split
メソッドで分割したい正規表現
を指定するとその内容に従って分割されます.
左の例では,split
メソッドに","
を渡しています.
これにより,item1
に代入されている文字列を","
で分割し,items1
というString
型の配列に代入しています.
items1
の長さ(items.length
)は2です.
item1
に代入されている文字列には,コンマが1つ存在し,
その前後の文字列が配列の0番目の要素,1番目の要素に代入されるためです.
一方,item2
は、最初の値の後ろは何も値がありません.
この場合,split
メソッドを用いてコンマ(","
)
で分割したとしても,items2
の長さは1になります.
後ろに値がない場合はこのような挙動になることに注意してください.
1-C-2. 文字列をInteger
型に変換する
String value = "10"; Integer integetValue = new Integer(value);
String
型で表現された"10"
を
Integer
型に変換するには,左のように書きましょう.
1-C-3. 文字列をDouble
型に変換する
String value = "56.149"; Double doubleValue = new Double(value);
String
型で表現された"56.149"
を
Double
型に変換するには,左のように書きましょう.
1-C-4. Integer
型同士の比較
Integer num1 = 1; Integer num2 = new Integer("1"); System.out.println(num1 == num2); // 「false」が出力される。 System.out.println(Objects.equals(num1, num2)); // 「true」が出力される。
実は、Integer
型もString
型と同じく、
アドレスであり、==
での指し示す先の一致性では、
内容の一致性は判定できません。内容の一致性判定には、
Objects.equals
を利用します。
1-C-5. IDの抜けについて
IDが連続して抜けていた場合の処理も考えてみましょう。 次の2通りの考え方があります。
-
Map
のキーにID、バリューに点数を入れることを考えます。 ファイルを全部読み、IDと点数をMap
に格納します。 その際、最大値を覚えておきます。 その後、1から最大値まで順にMap
から点数を取得すると良いでしょう。 - 現在の行番号を数える変数を用意します。 ファイルを1行ずつ読み、行番号とIDを比較します(1-C-4を参照)。 一致しなければ、行番号がIDになるまでKを出力します。
2. 最終成績を算出してください。
2-A. 問題説明
プログラムの実行時に,引数に試験成績(exam.csv
),
課題(assignments.csv
),
小テスト(miniexam.csv
)の3つのcsvファイルが渡されます.
それらの点数を読み,秀,優,良,可,不可,K(未受験)のグレードを判定してください. 最終成績の算出方法は,定期試験が70%,課題が25%,小テストの受験率が5%です. 小数点以下は切り上げてください.
ファイル名は,GradeChecker2.java
としてください.
なお,入力ファイルの行数が増減した場合でも適切に処理が行えるようにしてください.
それぞれのcsvファイルの内容は次の通りです.
2-A-1. 試験成績
$ cat exam.csv 1,70.05347594 3,86.09625668 4,85.02673797 5,56.14973262 ... 以下略
試験成績のcsvファイルでは,IDは番号順に並んでいますが,番号が飛んでいる場合があります. その場合は,飛んだ番号は未受験であるため,0点,Kと出力してください.
2-A-2. 課題
$ cat assignments.csv 1,10,8,8,10,8,10 2,,,,,, 3,8,9,8,,,10 4,8,10,10,8,10,10 5,10,10,,0,10, ... 以下略
左の各行は,「ID,課題1,課題2,課題3,課題4,課題5,課題6」の順に各課題の成績が記載されています. 点数が記載されていない部分は未提出です. 課題1〜6までの点数を合計した点数がその人の課題点であり,最高点は60点です. IDは昇順に並んでおり,途中に抜けている番号はありません.
2-A-3. 小テスト
$ cat miniexam.csv 1,5,2,,1,2,2,,1,5,0,0,5,0,2 2,5,3,1,,1,0,,0,3,,,,0,1 4,7,2,8,6,9,4,,4,,2,6,6,0, 5,3,5,7,,3,5,,1,3,,2,4,0,0 6,6,8,10,8,,,7,10,9,8,5,7,0, ... 以下略
各行は,IDから始まり,14回分の小テストの点数が記載されています. 点数の記載がない部分は小テストを未受験であり,0は受験したものの点数が取れなかったことを表しています. また,IDは昇順に並んでいますが,途中飛んでいる場合もあります.
この小テストでは,受験率を算出してください. すなわち,書かれている点数は重要ではなく,点数が書かれているか否かが重要です. 受験回数を14で割り,受験率を算出してください.その受験率を小テストの点数とします.
2-A-4. 成績の算出
プログラムには,コマンドライン引数で exam.csv
,assignments.csv
,
miniexam.csv
の順にファイルが指定されます.
IDが$n$の学生の最終成績$s$を次の式で算出してください.$e$が定期試験の点数,$a$が課題の合計点,$t$が小テストの受験率(0.0〜1.0)とします.
\[ s=\frac{70}{100}e + \frac{25}{60}a + 5t \]
Double givenValue = 17.01; Double ceiledValue = Math.ceil(givenValue); // ceiledValueには 18.0 が代入される.
最終成績$s$は小数点以下を切り上げてください.
切り上げは,左のように,Math.ceil
を利用してください.
また,グレード算出の時にKか不可かを判定するため, 定期試験を受験したか否かのフラグを保持しておくと良いでしょう.
2-B. 実行例
$ java GradeChecker2 exam.csv assignments.csv miniexam.csv 1,76,70.053,54,12,良 2, 4,0.000,0,9,不可 3,75,86.096,35,0,良 4,87,85.027,56,11,優 5,56,56.150,30,11,不可 6,71,68.984,45,11,良 ... 以下略 $ java GradeChecker2_2 exam.csv assignments.csv miniexam.csv 1,76,70.053,54,12,良 2, 4,,0,9,K 3,75,86.096,35,0,良 4,87,85.027,56,11,優 5,56,56.150,30,11,不可 6,71,68.984,45,11,良 ... 以下略
出力例を左に示します. IDの昇順になるように出力してください. 各行は,ID,最終成績,試験の点数,課題の合計点,小テストの受験回数, グレードをコンマ区切りで出力してください.
左のID 2の学生のように, 試験を受けていない場合は,単純に0点と考えて出力しても構いません. しかし,厳密にいえば,受験していないため,Kという判断をする方が良いです.
3. 全体の統計情報を算出してください。
3-A. 問題説明
2. 最終成績を出力して下さい.までに出力した内容の統計情報を出力しましょう. 統計情報とは,各学生の最終成績の平均,最高,最低点を算出してください. ただし,K,不可の学生を含めた場合と含めない場合での点数の両方を算出しましょう.
次に,各グレードに何人が属しているかを数えて出力してください.
ファイル名は,GradeChecker3.java
としてください.
なお,入力ファイルの行数が増減した場合でも適切に処理が行えるようにしてください.
3-B. 実行例
$ java GradeChecker3 exam.csv assignments.csv miniexam.csv 1,76,70.053,54,12,良 2, 4,,0,9,K 3,75,86.096,35,0,良 4,87,85.027,56,11,優 5,56,56.150,30,11,不可 6,71,68.984,45,11,良 ... 途中省略 149,92,93.583,54,9,秀 150,80,76.471,58,6,優 151, 0,,0,0,K 152,64,60.963,38,14,可 Avg: 63.224 (78.226) Max: 96.000 (96.000) Min: 0.000 (60.000) 秀: 11 優: 37 良: 41 可: 17 不可: 26 K: 20
出力例を左に示します.IDの昇順になるように出力してください. 各行は,ID,最終成績,試験の点数,課題の合計点,小テストの受験回数, グレードをコンマ区切りで出力してください.
すべての学生の成績を出力し終えたら,統計情報を出力してください. 統計情報は,最終成績の平均,最大,最小です. カッコ内の情報は,単位取得者(最終成績が60点以上)のみを対象に求めた平均,最大,最小です.
それらを出力し終えたら,今度は,各グレードに属する人数を出力してください.
4. 特別ルールを適用して最終成績を算出してください。
4-A. 問題説明
この講義の成績算出には,特別ルールが適用されます. それは,定期試験の素点が80点以上であれば,最終成績をその点数とする,というものです. ただし,2. 最終成績を出力して下さい.で算出した成績の方が上であれば, その成績を最終成績とします.
また,グレードに※を追加してください.※は出席日数不足を表しています. 条件は,定期試験を受験し,最終成績が60点未満かつ,小テストの受験回数が7回以下の場合に,グレードを※とします. 定期試験を受験していない学生のグレードはKとしてください.
この特別ルールを適用したプログラムを作成してください.
ファイル名は,GradeChecker4.java
とします.
なお,入力ファイルの行数が増減した場合でも適切に処理が行えるようにしてください.
4-B. 実行例
$ java GradeChecker4 exam.csv assignments.csv miniexam.csv 1,76,70.053,54,12,良 2, 4,,0,9,K 3,87,86.096,35,0,優 4,87,85.027,56,11,優 5,57,56.150,30,11,不可 6,71,68.984,45,11,良 7,76,75.936,48,6,良 8,84,83.957,38,11,優 9,36,32.086,26,5,※ ... 途中省略 149,94,93.583,54,9,秀 150,80,76.471,58,6,優 151, 0,,0,0,K 152,64,60.963,38,15,可 Avg: 65.868 (80.027) Max: 96.000 (96.000) Min: 0.000 (60.000) 秀: 14 優: 49 良: 35 可: 13 不可: 8 K: 20 ※: 13
3. 全体の統計情報を算出してください。までは, IDが3の学生の最終成績は75でした. ここでの特別ルールを適用すると,テストの点数が 86.096 ですので,この点数を切り上げ, 87点が最終成績となっています.
一方,IDが4の学生を見てみると,テストの点数が 85.027 と 80 点を超えています. しかし,2. 最終成績を出力して下さい. で計算した点数の方が高いため, 最終成績が87になっています.
また,IDが5の学生と9の学生では,最後の小テストの受験回数の違いが,グレードの違いになっています. さらに,グレードが一つ追加されたため,統計情報にも変更が加わっています.
5. オプション解析を行ってください。
5-A. 問題説明
今までは,コマンドライン引数でexam.csv
,assignments.csv
,
miniexam.csv
の順でファイルが渡されていました.
これを自由な順序で指定するようにプログラムを変更します.
しかし,本当に自由な順序で渡されるとどのファイルに何が書かれているのかがわかりませんので,
コマンドライン引数でファイルを指定しましょう.
- 成績のファイルを
-record
オプションで受け取ってください. - 課題のファイルを
-assignments
オプションで受け取ってください. - 小テストのファイルを
-miniexam
オプションで受け取ってください. - 出力先を
-output
オプションで受け取ってください.
ファイルが指定されない場合は,その成績は0点として最終成績を算出してください.
最終成績の計算式は変更する必要はありません.
また,-output
オプションが指定された場合は,そのファイルに結果を出力してください.
指定されなかった場合は,標準出力に出力してください.
ファイル名は,GradeChecker5.java
としてください.
なお,入力ファイルの行数が増減した場合でも適切に処理が行えるようにしてください.
5-B. 実行例
$ java GradeChecker5 -record exam.csv \ -assignments assignments.csv -output result.csv $ cat result.csv 1,72,70.053,54,0,良 2, 0,,0,0,K 3,87,86.096,35,0,優 4,86,85.027,56,0,優 5,57,56.150,30,0,※ 6,69,68.984,45,0,可 ... 途中省略 149,94,93.583,54,0,秀 150,78,76.471,58,0,良 151, 0,,0,0,K 152,61,60.963,38,0,可 Avg: 64.539 (78.800) Max: 96.000 (96.000) Min: 0.000 (61.000) 秀: 11 優: 43 良: 38 可: 18 不可: 0 K: 20 ※: 22
コマンド入力の途中で改行するには,左図のように,\の後ろで改行してください.改行がエスケープされます.
左の実行例では,小テストのファイルを指定せずに成績を算出し,結果をresult.csv
に出力するよう指定しています.
もちろん,-output
オプションが指定されなければ,
今まで通り標準出力に出力されます.
小テストが指定されていないため,出力の小テストの列はすべて0になっています. また,最終成績が60点以下であれば,グレードが※になっています.
6. その他の統計情報を算出してください。
6-A. 問題説明
次の統計情報と,
最終成績の順位を算出してください.
ファイル名は,GradeChecker6.java
としてください.
なお,入力ファイルの行数が増減した場合でも適切に処理が行えるようにしてください.
- 単位取得率
- 各グレードの人数の全体に占める割合
- 秀,優,良,可の人数の単位取得者に占める割合
6-A-1. 単位取得率
単位取得者の人数を数え,全体の学生数で割ってください. これで単位取得率が算出できます.統計情報として百分率(パーセンテージ)で出力してください.
6-A-2. 各グレードの人数の全体に占める割合
秀,優,良,可,不可,K,※の6種類のグレードが算出されています. 各グレードに属する人数が,全体のうちどれくらいの割合であるのかを算出してください. グレードの人数と同じ行に百分率(パーセンテージ)で出力してください.
6-A-3. 秀,優,良,可の人数の単位取得者に占める割合
秀,優,良,可の4種類のグレードについては, 各グレードに属する人数が,単位取得者のうちどれくらいの割合を占めているのかを算出してください. グレードの人数と同じ行に百分率(パーセンテージ)で出力してください.
6-A-4. 最終成績の順位
最終成績でソートし,学生に順位をつけてください. 各学生の成績を出力するときに,順位を行の最後につけて出力してください. 同じ点数であったとしても,同じ順位である必要はありません. 学生の情報を表す型が用意されている時,次のプログラムでソートが行えます.
学生の情報を表す型がStudent
,最終成績が Student
型の変数score
であるとします.
import java.util.Comparator; public class StudentComparator implements Comparator<Student>{ public int compare(Student s1, Student s2){ Double v1 = s1.score; Double v2 = s2.score; if(v1 < v2) return -1; else if(v1 > v2) return 1; return 0; } }
左のプログラムをStudentComparator.java
として保存し,GradeChecker6.java
と同じ場所に保存してください.
左のプログラムが2つの成績を比べる比較器です.
compare
が実際に比較するメソッドです.
今は,最終成績のみで比較していますが,その比較の前にグレードで比較すると良いでしょう.
s1 < s2
であれば負の値,s1 > s2
であれば正の値,
s1 == s2
であれば0を返すと,適切にソートしてくれます.
// listに学生の情報がすべて格納されている. List<Student> list = // ... // 先に作成した比較器. Comparator<Student> comp = new StudentComparator(); // 比較器を元にソートを行う. Collections.sort(list, comp);
その後,すべての学生情報が入ったList<Student>
を
Collections
型のsort
メソッドに渡してください.
そうすると,list
の順序がscore
の昇順に並び替えられています.
ただし,学生の情報を保存する独自の型は適宜読み替えてください.
また,最終成績が代入されている変数もここではscore
ですが,
自分自身で定義したものに置き換えてください.
なお,この場合,総合点のみでソートするため,Kと不可,※は順不同で出力されます.
グレードが秀,優,良,可,不可,K,※の順で並ぶようなプログラムにするにはどのようにすれば良いかを考えてみましょう.
StudentCompare
のcompare
メソッドをどのように変更すれば良いかを考えてみてください.
6-B. 実行例
$ java GradeChecker6 -miniexam miniexam.csv \ -record exam.csv -assignments assignments.csv 1,76,70.053,54,12,良,81 2, 4,,0,9,K,141 3,87,86.096,35,0,優,29 4,87,85.027,56,11,優,28 5,57,56.150,30,11,不可,118 6,71,68.984,45,11,良,96 7,76,75.936,48,6,良,80 8,84,83.957,38,11,優,41 9,36,32.086,26,5,※,130 ... 途中省略 149,94,93.583,54,9,秀,4 150,80,76.471,58,6,優,55 151, 0,,0,0,K,145 152,64,60.963,38,15,可,107 Avg: 65.868 (80.027) Max: 96.000 (96.000) Min: 0.000 (60.000) 単位取得率: 73.026% 秀: 14 (9.211%, 12.613%) 優: 49 (32.237%, 44.144%) 良: 35 (23.026%, 31.532%) 可: 13 (8.553%, 11.712%) 不可: 8 (5.263%) K: 20 (13.158%) ※: 13 (8.553%)
各行に学生の成績が出力されます.行のフォーマットは, 「ID,最終成績,試験の点数,課題の点数,小テストの受験回数,グレード,順位」です.
すべての学生の成績の出力後に,統計情報が出力されています. 最終成績の平均,最大値,最小値です. カッコ内の値は,単位取得者に限った時の最終成績の平均,最大値,最小値です.
次に単位取得率が出力されています.
最後に各グレードに属する人数とその割合が出力されています. 秀,優,良,可のカッコ内にある2つの数値は,全体におけるその人数の割合と単位取得者におけるその人数の割合です. 不可,K,※は,全体におけるその人数の割合が出力されています.
例えば,例の場合,全体の人数は152名で,単位取得者の人数は111名,秀の人数は14名です. 単位取得率は73.026%($=\frac{111}{152}$)です. また,全体に占める秀の人数の割合は,9.211%($=\frac{14}{152}$), 単位取得者に占める秀の人数の割合は12.613%($=\frac{14}{111}$)です.