以下のステップを実行する前に,概要の 課題のデータから必要なデータをダウンロードしておいてください.
プログラムの実行時に,引数に試験成績のcsvファイル(exam.csv)が渡されます.
csvファイルは,IDと点数が記載されています.
その点数を読み,秀,優,良,可,不可,K(未受験)のグレードを判定してください.
IDは番号順に並んでいますが,番号が飛んでいる場合があります.
その場合は,飛んだ番号は未受験であるため,0点,Kと出力してください.
ただし,最後の行のIDが最後のIDであると信用しても構いません.
点数が60点未満が不可,60以上70点未満が可,70点以上80点未満が良,80点以上90点未満が優, 90点以上が秀です.
K(未受験)はexam.csvに掲載されていません.
IDが飛んだ時,その学生のグレードをKにしてください.
ファイル名は,GradeChecker1.javaとしてください.
なお,入力ファイルの行数が増減した場合でも適切に処理が行えるようにしてください.
$ 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, 不可
# ... 以下略
$ java GradeChecker1 exam2.csv # ファイルが exam.csv ではなくてもOK
1,78.053, 良
2,44.321, 不可
3,61.027, 可
4,17.150, 不可
5,82.096, 優
# ... 以下略
$ java GradeChecker1 # 何も指定しなかった場合は,エラーメッセージを表示する.
ERROR: 試験の成績ファイルが指定されていません.
java GradeChecker1 <EXAM.CSV>
IDが昇順になるように出力してください. 「ID, 最終成績,グレード」をコンマ区切りで出力してください.
なお,上の実行結果からもわかるように,exam.csvには,ID 2が抜けています.
そのため,2番目の学生は未受験であるため,出力では,2番の学生は0点でグレードがKになっています.
また,与えられるファイルの名前は exam.csvであるとは限りません.
String型)からInteger型への変換String型)からDouble型への変換HashMapの使い方split)IDが連続して抜けていた場合の処理も考えてみましょう。 次の2通りの考え方があります。
HashMapのキーにID,バリューに点数を入れることを考えます.
HashMapに格納します.HashMapから点数を取得してみましょう.プログラムの実行時に,引数に試験成績(exam.csv), 課題(assignments.csv),小テスト(miniexam.csv)の3つのcsvファイルが渡されます.
それらの点数を読み,秀,優,良,可,不可,K(未受験)のグレードを判定してください. 最終成績の算出方法は,定期試験が70%,課題が25%,小テストの受験率が5%です.小数点以下は切り上げてください.
ファイル名は,GradeChecker2.javaとしてください.
なお,入力ファイルの行数が増減した場合でも適切に処理が行えるようにしてください.
それぞれのcsvファイルの内容は次の通りです.
$ cat exam.csv
1,70.05347594
3,86.09625668
4,85.02673797
5,56.14973262
# ... 以下略
$ 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は昇順に並んでおり,途中に抜けている番号はありません.
$ 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で割り,受験率を算出してください. その受験率を小テストの点数とします.
プログラムには,コマンドライン引数で 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つの要件を満たすようにプログラムを作成してください.
GradeChecker2.java のフィールドが5つ以下になるようにしてください.GradeChecker2.java のそれぞれのメソッドにおいても,宣言する変数が5つ以下になるようにしてください.)$ java GradeChecker2 exam.csv assignments.csv miniexam.csv
1,76.0,70.05347594,54.0000,0.857143,良
2,4.0,,0.00000,0.642857,K
3,75.0,86.09625668,35.0000,0.00000,良
4,87.0,85.02673797,56.0000,0.785714,優
5,56.0,56.14973262,30.0000,0.785714,不可
6,71.0,68.98395722,45.0000,0.785714,良
7,76.0,75.93582888,48.0000,0.428571,良
8,79.0,83.95721925,38.0000,0.785714,良
9,36.0,32.0855615,26.0000,0.357143,不可
10,58.0,50.80213904,51.0000,0.0714286,不可
11,71.0,68.98395722,43.0000,0.928571,良
# ... 以下略
$ java GradeChecker2 # ファイルが3つ指定されなかった場合は,エラーメッセージを表示する.
ERROR: 必要なファイルが指定されていません.
java GradeChecker2 <EXAM.CSV> <ASSIGNMENTS.CSV> <MINIEXAM.CSV>
出力例を上に示します. IDの昇順になるように出力してください. 各行は,ID,最終成績,試験の点数,課題の合計点,小テストの受験回数,グレードをコンマ区切りで出力してください.
実行例にあるID 2の学生のように,試験を受けていない場合は K として扱ってください. なお,試験を受験したが,0点である場合もあることに注意してください.
Student.javaを定義し,フィールドに examScore, assignments, miniexams,id を宣言します.
Double finalScore() メソッドは,examScore, assignments, miniexamsを元に最終成績の点数を算出しましょう.String grade() メソッドは,finalScoreメソッドの結果を元に秀優良可不可を算出しましょう.
examScoreがnullであればKと判断しましょう.ステップ2までに出力した内容の統計情報を出力しましょう. 統計情報とは,全学生の最終成績の平均,最高,最低点を算出してください. ただし,K,不可の学生を含めた場合と含めない場合での点数の両方を算出しましょう.
次に,各グレードに何人が属しているかを数えて出力してください.
ファイル名は,GradeChecker3.javaとしてください.
なお,入力ファイルの行数が増減した場合でも適切に処理が行えるようにしてください.
$ java GradeChecker3 exam.csv assignments.csv miniexam.csv
1,76.0,70.05347594,54.0000,0.857143,良
2,4.0,,0.00000,0.642857,K
3,75.0,86.09625668,35.0000,0.00000,良
4,87.0,85.02673797,56.0000,0.785714,優
5,56.0,56.14973262,30.0000,0.785714,不可
6,71.0,68.98395722,45.0000,0.785714,良
# ... 途中省略
149,92.0,93.5828877,54.0000,0.642857,秀
150,80.0,76.47058824,58.0000,0.428571,優
151,1.0,,0.00000,0.0714286,K
152,64.0,60.96256684,38.0000,1.00000,可
Avg: 63.2303 (78.2264)
Max: 96.0000 (96.0000)
Min: 0.00000 (60.0000)
秀: 11
優: 37
良: 41
可: 17
不可: 26
K: 20
出力例を上に示します. IDの昇順になるように出力してください. 各行は,ID,最終成績,試験の点数,課題の合計点,小テストの受験回数,グレードをコンマ区切りで出力してください.
すべての学生の成績を出力し終えたら,統計情報を出力してください. 統計情報は,最終成績の平均,最大,最小です. カッコ内の情報は,単位取得者(最終成績が60点以上)のみを対象に求めた平均,最大,最小です.
それらを出力し終えたら,今度は,各グレードに属する人数を出力してください.
Statsを作成しましょう.
max,最小値を表すmin,追加された値の合計値を表すsum,追加された数を表すcountの4つのフィールドを定義しましょう.averageメソッド,maxメソッド,minメソッド,putメソッド.putメソッドで点数をうけとりましょう.
sumに追加された値を加算しましょう.count に 1を加算しましょう.Statsの実体を作成しましょう.
Statsの実体のputメソッドに全てのStudentのfinalScoreの値を渡しましょう.gradeメソッドが"K"ではない場合に,もう一方のStatsの実体のputメソッドに最終成績を渡しましょう.この講義の成績算出には,特別ルールが適用されます. それは,定期試験の素点が80点以上であれば,最終成績をその点数とする,というものです. なお,定期試験の点数も切り上げて判定してください. すなわち,定期試験の点数が 79を超えていれば,切り上げにより80点隣,上記の定期試験の素点が80点を超える,というルールに該当するようになります. ただし,ステップ2 で算出した成績の方が上であれば,その成績を最終成績とします.
また,グレードに※を追加してください.
※は出席日数不足を表しています.
条件は,定期試験を受験し,最終成績が60点未満かつ,小テストの受験回数が7回以下の場合に,グレードを※とします.
定期試験を受験していない学生のグレードはKとしてください.
この特別ルールを適用したプログラムを作成してください.
ファイル名は,GradeChecker4.javaとします.
なお,入力ファイルの行数が増減した場合でも適切に処理が行えるようにしてください.
$ java GradeChecker4 exam.csv assignments.csv miniexam.csv
1,76.0,70.05347594,54.0000,0.857143,良
2,4.0,,0.00000,0.642857,K
3,87.0,86.09625668,35.0000,0.00000,優 # ステップ3までは,この学生の最終成績は75だが,特別ルールで87になった.
4,87.0,85.02673797,56.0000,0.785714,優 # テストの点数が80点を超えているが,計算した点数の方が高いため,87が最終成績となっている.
5,56.0,56.14973262,30.0000,0.785714,不可
6,71.0,68.98395722,45.0000,0.785714,良
7,76.0,75.93582888,48.0000,0.428571,良
8,84.0,83.95721925,38.0000,0.785714,優
9,36.0,32.0855615,26.0000,0.357143,※ # 受験回数が少ないため,最終成績が※となっている.
# ... 途中省略
18,80.0,79.67914439,43.0000,0.0714286,優 # 試験が79.679... で ceil すると 80点になる.計算した点数が75点であるため,特別ルールで80点となる.
# ... 途中省略
149,94.0,93.5828877,54.0000,0.642857,秀
150,80.0,76.47058824,58.0000,0.428571,優
151,1.0,,0.00000,0.0714286,K
152,64.0,60.96256684,38.0000,1.00000,可
Avg: 64.3026 (79.7642)
Max: 96.0000 (96.0000)
Min: 0.00000 (60.0000)
秀: 14
優: 49
良: 27
可: 16
不可: 9
K: 20
※: 17
Student型のfinalScoreメソッド,gradeメソッドを変更すると良いでしょう.
Student4とクラス名を変更しておきましょう.※の頻度を追加することで完成です.今までは,コマンドライン引数でexam.csv,assignments.csv,miniexam.csvの順でファイルが渡されていました.
これを自由な順序で指定するできるようにプログラムを変更します.
しかし,本当に自由な順序で渡されるとどのファイルに何が書かれているのかがわかりませんので,コマンドライン引数でファイルを指定しましょう.
成績のファイルを -examオプションで受け取ってください.
課題のファイルを -assignmentsオプションで受け取ってください.
小テストのファイルを -miniexamオプションで受け取ってください.
出力先を-outputオプションで受け取ってください.
ファイルが指定されない場合は,その成績は0点として最終成績を算出してください.
最終成績の計算式は変更する必要はありません.
また,-outputオプションが指定された場合は,そのファイルに結果を出力してください.
指定されなかった場合は,標準出力に出力してください.
ファイル名は,GradeChecker5.javaとしてください.
なお,入力ファイルの行数が増減した場合でも適切に処理が行えるようにしてください.
ファイル名がexam.csv,miniexam.csv,assignments.csvであるとは限りません.
なお,一つもファイルが指定されなかった場合は,エラーメッセージを表示して終了してください.
$ java GradeChecker5 -exam exam.csv -assignments assignments.csv -output result.csv
$ cat result.csv
1,72.0,70.05347594,54.0000,0.00000,良
2,0.0,,0.00000,0.00000,K
3,87.0,86.09625668,35.0000,0.00000,優
4,86.0,85.02673797,56.0000,0.00000,優
5,52.0,56.14973262,30.0000,0.00000,※
6,68.0,68.98395722,45.0000,0.00000,可
# ... 途中省略
149,94.0,93.5828877,54.0000,0.00000,秀
150,78.0,76.47058824,58.0000,0.00000,良
151,0.0,,0.00000,0.00000,K
152,59.0,60.96256684,38.0000,0.00000,※
Avg: 62.2829 (78.5098)
Max: 96.0000 (96.0000)
Min: 0.00000 (60.0000)
秀: 11
優: 43
良: 27
可: 21
不可: 0
K: 20
※: 30
$ java GradeChecker5
ERROR: 何もファイルが指定されていません.
java GradeChecker5 [OPTIONS]
OPTIONS
-exam <EXAM.CSV>
-assignments <ASSIGNMENTS.CSV>
-miniexam <MINIEXAM.CSV>
-output <RESULT_FILE>
左の実行例では,小テストのファイルを指定せずに成績を算出し,結果を result.csv に出力するよう指定しています.
もちろん,-outputオプションが指定されなければ,今まで通り標準出力に出力されます.
小テストが指定されていないため,出力の小テストの列はすべて0になっています.
また,最終成績が60点以下であれば,小テストの受験回数が0回ですので,グレードが※になっています.
それに伴い,不可の人数が0人となっています(不可に割り当てられる学生は,小テストの回数が0点であるため,※となる.).
また,定期試験のファイルが指定されなかった場合,全員が未受験扱いとなるため,全員がKと判定されます.
Arguments型を作成しましょう.
String型の examString型の miniexamString型の assignmentsString型の outputPrintWriter型の outvoid parse(String[] args) メソッドを用意しましょう.
-examや-assignments,-miniexam,-outputが指定された場合は,インデックスを1つ進めて,変数に代入しましょう.PrintWriterを作成して返す createPrintWriterメソッドを用意しましょう.
outputが指定されているか否かで分岐させましょう.
outputが指定されていれば,指定されたファイルをFileWriterで開き,PrintWriterでラップして返しましょう.outputが指定されていなければ,System.outをPrintWriterでラップして返しましょう.PrintWriterを返す outメソッドを用意しましょう.
outがnullであれば,createPrintWriterを呼び出して,outに代入しましょう.outを返しましょう.void parse(String[] args){
for(Integer i = 0; i < args.length; i++){
// 途中省略
else if(/* -exam が指定された場合の条件式 */){
i++;
this.exam = args[i];
}
// 途中省略
}
}
次の統計情報と, 最終成績の順位を算出してください.
ファイル名は,GradeChecker6.javaとしてください.
なお,入力ファイルの行数が増減した場合でも適切に処理が行えるようにしてください.
最終成績でソートし,学生に順位をつけてください. 各学生の成績を出力するときに,順位を行の最後につけて出力してください. 同じ点数であったとしても,同じ順位である必要はありません. 学生の情報を表す型が用意されている時,次のプログラムでソートが行えます.
学生の情報を表す型がStudent4,最終成績が Student4型のfinalScoreメソッドで算出できるとします.
import java.util.Comparator;
public class StudentComparator implements Comparator<Student4>{
public int compare(Student4 student1, Student4 student2){
Double score1 = student1.finalScore();
Double score2 = student2.finalScore();
if(score1 < score2) return 1;
else if(score1 > score2) return -1;
return 0;
}
}
このプログラムをStudentComparator.javaとして保存し,GradeChecker6.java と同じ場所に保存してください.
このプログラムが2つの成績を比べる比較器であり,compareメソッドが実際に比較するメソッドです.
score1 > score2であれば負の値,score1 < score2であれば正の値,score1 == score2であれば0を返すと,適切に降順にソートしてくれます.
返り値の符号がが逆転すると,逆順ソート(昇順)のソートになります.
// listに学生の情報がすべて格納されている.
ArrayList<Student4> list = // ...
// 先に作成した比較器.
Comparator<Student4> comp = new StudentComparator();
// 比較器を元にソートを行う.
Collections.sort(list, comp);
このプログラムが,StudentComparatorを利用する側のプログラムの断片です.
すべての学生情報が入ったArrayList<Student4>を Collections型のsortメソッドにStudentComparatorの実体と共に渡してください.
そうすると,listの順序が最終成績の昇順に並び替えられています.
ただし,学生の情報を保存する独自の型は適宜読み替えてください.
また,最終成績が得られるメソッドもここではfinalScoreメソッドですが,自分自身で定義したものに置き換えてください.
なお,この場合,総合点のみでソートするため,Kと不可,※は順不同で出力されます.
グレードが秀,優,良,可,不可,K,※の順で並ぶようなプログラムにするにはどのようにすれば良いかを考えてみましょう.
StudentCompareのcompareメソッドをどのように変更すれば良いかを考えてみてください.
$ java GradeChecker6 -miniexam miniexam.csv -exam exam.csv -assignments assignments.csv
1,76.0,70.05347594,54.0000,0.857143,良,71
2,4.0,,0.00000,0.642857,K,141
3,87.0,86.09625668,35.0000,0.00000,優,24
4,87.0,85.02673797,56.0000,0.785714,優,25
5,56.0,56.14973262,30.0000,0.785714,不可,110
6,71.0,68.98395722,45.0000,0.785714,良,85
7,76.0,75.93582888,48.0000,0.428571,良,72
8,84.0,83.95721925,38.0000,0.785714,優,36
9,36.0,32.0855615,26.0000,0.357143,※,129
# ... 途中省略
149,94.0,93.5828877,54.0000,0.642857,秀,5
150,80.0,76.47058824,58.0000,0.428571,優,63
151,1.0,,0.00000,0.0714286,K,145
152,64.0,60.96256684,38.0000,1.00000,可,101
Average: 64.3026 (79.7642)
Max: 96.0000 (96.0000)
Min: 0.00000 (60.0000)
単位取得率: 69.7% (106/152)
秀: 14 (9.2105% (14/152), 13.208% (14/106))
優: 49 (32.237% (49/152), 46.226% (49/106))
良: 27 (17.763% (27/152), 25.472% (27/106))
可: 16 (10.526% (16/152), 15.094% (16/106))
不可: 9 (5.9211% ( 9/152))
K: 20 (13.158% (20/152))
※: 17 (11.184% (17/152))
各行に学生の成績が出力されます. 行のフォーマットは,「ID,最終成績,試験の点数,課題の点数,小テストの受験回数,グレード,順位」です.
すべての学生の成績の出力後に,統計情報が出力されています. 最終成績の平均,最大値,最小値です. カッコ内の値は,単位取得者に限った時の最終成績の平均,最大値,最小値です.
次に単位取得率が出力されています.
最後に各グレードに属する人数とその割合が出力されています. 秀,優,良,可のカッコ内にある2つの数値は,全体におけるその人数の割合と単位取得者におけるその人数の割合です. 不可,K,※は,全体におけるその人数の割合が出力されています.
例えば,例の場合,全体の人数は152名で,単位取得者の人数は106名,秀の人数は12名です. 単位取得率は73.026%($=\frac{111}{152}$)です. また,全体に占める秀の人数の割合は7.8947%($=\frac{12}{152}$), 単位取得者に占める秀の人数の割合は11.321%($=\frac{12}{106}$)です.
順位を求めるには,学生を点数で降順にソートし,順位を保存しておく必要があります.
Student4型にInteger型のrankという変数を追加しましょう.順位を保存しておく変数です.StudentComparatorの実体を作成しましょう.ArrayList<Student4>型の変数listを用意しましょう.
HashMap<Integer, Student4>型のmapに入れているのであれば,list.addAll(map.values())で用意できます.ArrayList<Student4>型のstudentsに入れているのであれば,list.addAll(students)で用意できます.
Collections.sortメソッドを用いて,listをStudentComparatorを用いてソートしましょう.listの各要素のStudent4型のrankに順位をつけていきましょう.