以下のステップを実行する前に,概要の 課題のデータから必要なデータをダウンロードしておいてください.
コマンドライン引数で与えられたデータ(複数可能)を読み,以下の分析結果を出力してください.
なお,データの各桁は,次の項目があり,各行には,各桁の値が記入されています. ただし,空欄の場合もありますので,注意してください.
$ java MovieAnalyzer1 movie1.csv
1915,1
1931,2
# 途中省略
2015,1
2016,1
2017,2
$ java MovieAnalyzer1 movie2.csv
1910,1
1920,1
# 途中省略
2015,7
2016,6
2017,5
$ java MovieAnalyzer1 movie1.csv movie2.csv
1910,1
1915,1
# 途中省略
2015,8
2016,7
2017,7
$ java MovieAnalyzer1 # 何も出力されない.
年と対応する作品数を記録するために典型的にはMap
を利用します.
Map
はその実装によりHashMap
とTreeMap
に分けられます.
HashMap
は並び順は一切考慮されません.
一方,TreeMap
はキーの辞書順で並べられます.
そのため,HashMap
ではなく,TreeMap
を使いましょう.
今まで HashMap
と書いていた箇所を単純に TreeMap
に置き換えるだけで良いです.
次の流れで処理すれば良いでしょう.
TreeMap<Integer, Integer>
型の変数を宣言し,初期化する.,
)で区切る.Integer
型に変換する.TreeMap
型の変数に公開年をキーに映画の本数を受け取る.TreeMap
型の変数に再登録する.TreeMap
の要素を順に出力する.コマンドライン引数で何もデータが与えられなかった場合,標準入力からデータを受け取るようにしてください. 出力内容はステップ1と同様です.
$ java MovieAnalyzer2 movie1.csv # ステップ1の実行結果と同じ.
1915,1
1931,2
# 途中省略
2015,1
2016,1
2017,2
$ head -1 movie1.csv | java MovieAnalyzer2 # 1行のみ
1915,1
$ java MovieAnalyzer2 # 入力をキーボードから与える.
1997,"Princess Mononoke",Japan,"Hayao Miyazaki",,Animation,https://en.wikipedia.org/wiki/Princess_Mononoke,
# この行はキーボードから1行で入力する(途中で改行せず,最後のコンマの後ろで改行する).
# ダブルクォート(")も省略せず入力する.
[Ctrl-D] # Control + D を入力し,入力終了(EOF (End Of File) を送る).
1997,1 # この行が出力結果.
ファイルから読み取る時と標準入力から読み取る時の両方を BufferedReader
として扱えると処理が重複せずに済みます.
次のようなフローチャートで考えてみると良いでしょう.
ここで,分析処理と書かれている部分をBufferedReader
を引数として受け取るメソッドを定義し,そのメソッド内で分析を行うようにすると良いでしょう.
そのために,System.in
を開く,args[i]
を開くという処理で,BufferedReader
型の変数が得られるようにしましょう.
コマンドライン引数,もしくは標準入力から与えられたデータ(複数可能)を読み,以下の分析結果を出力してください.
ただし,Castの項目には複数の出演者が記載されている場合があります.
Genreの項目も同様に複数のジャンルが記載されている場合があります.
そのため,読み込んだ各行を単純に line.split(",")
とすると期待通りの結果が得られません.
そこで,CsvSplitter
というプログラムを用意しました.
MovieAnalyzer3.java
と同じディレクトリに置き,次のようなプログラムで期待通りの結果が得られます.
CsvSplitter splitter = new CsvSplitter();
// ...
ArrayList<String> items = splitter.split(line);
// lineが次の1行であった場合,
// item1, "item2.1, item2.2", item3
// => 分割結果は次の通り.
// item1
// item2.1, item2.2
// item3
ただし,以下の2つの要件を満たすようにプログラムを作成してください.
MovieAnalyzer3.java
のフィールドが4つ以下になるようにしてください.MovieAnalyzer3.java
のそれぞれのメソッドにおいても,宣言する変数が4つ以下になるようにしてください.$ java MovieAnalyzer3 movie1.csv
A Jie,1,[drama, animation, fantasy]
ANR,1,[unknown]
Aaron Eckhart,1,[action, sci-fi]
Adam Pally,1,[comedy]
Adele Jergens,1,[comedy]
# ...途中省略
Yusuf Khan,1,[action]
Zach Galligan,1,[horror]
Zeenat Aman,1,[action]
Zhang Yuanyuan,1,[drama, animation, fantasy]
$ java MovieAnalyzer3 # 標準入力から受け取る.
1997,"Princess Mononoke",Japan,"Hayao Miyazaki",,Animation,https://en.wikipedia.org/wiki/Princess_Mononoke,
[Ctrl-D] # 入力終了.キャスト部分に何も入力されていないため,何も出力されない.
$ head -2 movie3.csv | java MovieAnalyzer3
Edmund Gwenn,1,[comedy]
Elizabeth Taylor,1,[comedy]
Irene Dunne,1,[comedy]
James Raglan,1,[comedy]
William Powell,1,[comedy]
Cast.java
を定義し,フィールドに name
, count
, genres
を宣言します.
count
はInteger
型で0
で初期化しましょう.genres
はArrayList<String>
型であり,同じく初期化しておきましょう.void update(String genreString)
メソッドでは,ジャンルと出演数を更新します.
genreString
も複数のジャンルを含む可能性があります.
,
)もしくはスラッシュ(/
)で区切られます.genreString.split("[,/] *")
で分割可能です.MovieAnalyzer2
でデータを読むときには,Cast
の update
メソッドを呼び,必要な値を渡しましょう.Cast
を出力するためのString
を返すstring()
メソッドを用意しておくと良いでしょう.public class Stats{
// ... 途中省略
String string(){
return String.format("適切な文字列に置き換える");
}
}
printf
と同じように利用でき,結果を文字列として受け取れるようになるメソッドです.
String name = "Tamada";
String hello = String.format("Hello, %s", name);
// => hello には,"Hello, Tamada" が代入される.
与えられたデータを読み,与えられたオプションを元に適切な処理(主にフィルタリング)を行ってください.
$ java MovieAnalyzer4 --help
Usage: java MovieAnalyzer4 [OPTIONS] [Movie Files...]
-h, --help: このメッセージを表示する.
-c, --cast <Cast名>: ここで指定されたキャストでフィルタリングする(部分一致).
-t, --title <タイトル>: ここで指定されたタイトルでフィルタリングする(部分一致).
-h
もしくは,--help
が指定された場合は,上記のメッセージを表示してください.-c
もしくは,--cast
が指定された場合は,続いてキャスト名が指定されます.
指定された文字列を持つキャストでフィルタリングし,ステップ3と同じ結果を出力してください.-t
もしくは--title
が指定された場合は,続いてタイトルが指定されます.
指定された文字列を持つタイトルでフィルタリングし,ステップ3と同じ結果を出力してください.$ java MovieAnalyzer4 --help
Usage: java MovieAnalyzer4 [OPTIONS] [Movie Files...]
-h, --help: このメッセージを表示する.
-c, --cast <Cast名>: ここで指定されたキャストでフィルタリングする(部分一致).
-t, --title <タイトル>: ここで指定されたタイトルでフィルタリングする(部分一致).
$ java MovieAnalyzer4 -h # --help が指定された場合と同じ結果となる.
Usage: java MovieAnalyzer4 [OPTIONS] [Movie Files...]
-h, --help: このメッセージを表示する.
-c, --cast <Cast名>: ここで指定されたキャストでフィルタリングする(部分一致).
-t, --title <タイトル>: ここで指定されたタイトルでフィルタリングする(部分一致)
$ $ head -1 movie4.csv | java MovieAnalyzer4 # 何も指定されなければ標準入力から受け取る.
Saravanan,1,[unknown]
Suvarna Mathew,1,[unknown]
$ cat movie?.csv | java MovieAnalyzer4 -c 'Tom Cruise' # トムクルーズでフィルタリング.
Tom Cruise,3,[comedy, drama]
$ java MovieAnalyzer4 -t Pirates movie4.csv # タイトルにPiratesを含むもの.
Buster Crabbe,1,[serial]
Ian McShane,1,[action-adventure, family]
Johnny Depp,1,[action-adventure, family]
Kevin McNally and Geoffrey Rush,1,[action-adventure, family]
Lois Hall,1,[serial]
Penélope Cruz,1,[action-adventure, family]
Arguments
型を作成しましょう.
Boolean
型の help
String
型のcast
String
型の title
ArrayList<String>
型の arguments
void parse(String[] args)
メソッドを用意しましょう.
Arguments
のフィールドに値を代入しましょう.-c
や-t
が指定された場合は,インデックスを1つ進めて,変数に代入しましょう.void parse(String[] args){
for(Integer i = 0; i < args.length; i++){
// 途中省略
else if(/* -t もしくは --title が指定された場合の条件式 */){
i++;
this.title = args[i];
}
// 途中省略
}
}
キャストごとに出演作品をリストアップしましょう.
例えば,movie4.csv
には,Tom Cruiseが出演している映画が2作品リストアップされています.
それをキャストの次の行にリストアップしてみましょう.
次のような出力にしてください.
$ java MovieAnalyzer5 --cast 'Tom Cruise' movie4.csv
Tom Cruise,2,[comedy, drama] # キャスト名,出演作品数,ジャンル一覧
Losin' It [comedy] # [tab]タイトル [ジャンル]
Magnolia [drama] # [tab]タイトル [ジャンル]
$ cat movie4.csv | java MovieAnalyzer5 -t Pirates
Buster Crabbe,1,[serial]
Pirates of the High Seas [serial]
Ian McShane,1,[action-adventure, family]
Pirates of the Caribbean: On Stranger Tides [action-adventure, family]
Johnny Depp,1,[action-adventure, family]
Pirates of the Caribbean: On Stranger Tides [action-adventure, family]
Kevin McNally and Geoffrey Rush,1,[action-adventure, family]
Pirates of the Caribbean: On Stranger Tides [action-adventure, family]
Lois Hall,1,[serial]
Pirates of the High Seas [serial]
Penélope Cruz,1,[action-adventure, family]
Pirates of the Caribbean: On Stranger Tides [action-adventure, family]
$ cat movie*.csv | java MovieAnalyzer5 -c 'Tommy Lee Jones'
Tommy Lee Jones,6,[comedy, drama, musical comedy, action, biography, science fiction, fantasy]
Hope Springs [comedy]
The Package [drama]
A Prairie Home Companion [musical comedy]
Black Moon Rising [action]
Cobb [biography, drama]
Small Soldiers [science fiction, fantasy, action]
Cast.java
を修正すると,過去のプログラムの動作に影響が出ます.
そのため,Cast.java
をCast5.java
にコピーし,MovieAnalyzer5.java
ではCast
型の代わりにCast5
型を利用するようにプログラムを修正しましょう.
次に,タイトルとジャンルを格納する型Movie
を作成します.
そして,Cast5
では,Cast
が持つフィールドに加え,出演作品を表すArrayList<Movie>
型の変数movies
を追加しましょう.
また,update
メソッドでタイトルも受け取るようにし,movies
に作品を追加していきましょう.
最後に出力部分で,キャスト名を出力後に,出演タイトル一覧を出力するようにすれば良いです.
3つのオプション,--origin
, --genre
, --output
を追加してください.
Usage: java MovieAnalyzer4 [OPTIONS] [Movie Files...]
-h, --help: このメッセージを表示する.
-c, --cast <Cast名>: ここで指定されたキャストでフィルタリングする(部分一致).
-t, --title <タイトル>: ここで指定されたタイトルでフィルタリングする(部分一致)
-o, --origin <ORIGIN>: ここで指定された映画作成地域でフィルタリングする(部分一致,大文字小文字を区別しない).
-g, --genre <GENRE>: ここで指定されたジャンルでフィルタリングする(部分一致).
-O, --output <DEST>: ここで指定されたファイルに結果を出力する.
Cast5.java
をCast6.java
に,Movie.java
をMovie6.java
にコピーして始めましょう.
また,Cast6.java
内のMovie
をMovie6
に変更し,Movie6
にString
型のorigin
を追加しましょう.
また,Moivie6
のorigin
に必要な値を代入できるよう,MovieAnalyzer6
を修正しましょう.
$ java MovieAnalyzer6 movie3.csv -o japanese
Ai Kayano,1,[drama]
2016 Tamayura ~Sotsugyō Shashin~ Part 4: Ashita [drama] (Japanese)
Akemi Negishi,1,[war drama]
1953 Anatahan [war drama] (Japanese)
# 途中省略....
Yutaka Matsushige,1,[drama]
2000 Eureka [drama] (Japanese)
Yūko Kaida,1,[fantasy, drama, science fantasy]
2017 The Night Is Short, Walk on Girl [fantasy, drama, science fantasy] (Japanese)
$ java MovieAnalyzer6 --help
Usage: java MovieAnalyzer4 [OPTIONS] [Movie Files...]
-h, --help: このメッセージを表示する.
-c, --cast <Cast名>: ここで指定されたキャストでフィルタリングする(部分一致).
-t, --title <タイトル>: ここで指定されたタイトルでフィルタリングする(部分一致).
-o, --origin <ORIGIN>: ここで指定された映画作成地域でフィルタリングする(部分一致,大文字小文字を区別しない).
-g, --genre <GENRE>: ここで指定されたジャンルでフィルタリングする(部分一致).
-O, --output <DEST>: ここで指定されたファイルに結果を出力する.
$ java MovieAnalyzer6 movie3.csv -o japanese --genre fantasy
Gen Hoshino,1,[fantasy, drama, science fantasy]
2017 The Night Is Short, Walk on Girl [fantasy, drama, science fantasy] (Japanese)
Hiroshi Kamiya,1,[fantasy, drama, science fantasy]
2017 The Night Is Short, Walk on Girl [fantasy, drama, science fantasy] (Japanese)
Kana Hanazawa,1,[fantasy, drama, science fantasy]
2017 The Night Is Short, Walk on Girl [fantasy, drama, science fantasy] (Japanese)
Kazuya Nakai,1,[fantasy, drama, science fantasy]
2017 The Night Is Short, Walk on Girl [fantasy, drama, science fantasy] (Japanese)
Ryuji Akiyama,1,[fantasy, drama, science fantasy]
2017 The Night Is Short, Walk on Girl [fantasy, drama, science fantasy] (Japanese)
Yūko Kaida,1,[fantasy, drama, science fantasy]
2017 The Night Is Short, Walk on Girl [fantasy, drama, science fantasy] (Japanese)
大文字小文字で区別せずに比較するには,一旦両方を大文字(小文字)に変換して比較を行いましょう.
文字列を大文字に変換するにはtoUpperCase
メソッド,小文字に変換するにはtoLowerCase
メソッドを利用します.
String string = "Some cAsE";
String upper = string.toUpperCase(); // => upper には "SOME CASE"が代入される.
String lower = string.toLowerCase(); // => lower には "some case"が代入さえる.
大文字小文字を統一してから比較を行うことで,大文字小文字を区別せずに比較が行えるようになります.
Arguments
型に対して,以下の処理を行いましょう.
String
型のoutput
を宣言してください.PrintWriter
型のout
を宣言してください.初期値は代入しなくて良いです.Arguments
型のparse
メソッド)にて,出力先を Arguments
の output
に代入するようにしてください.PrintWriter
を返す writer
メソッドを用意しましょう.
out
に何も代入されていなければ(null
であれば),次の処理を行ってください.
output
に文字が代入されていれば,そのファイルを開き PrintWriter
型でラップして,out
に代入しましょう.
out = new PrintWriter(new FileWriter(output));
output
に文字が代入されていなければ,System.out
をPrintWriter
型でラップしてout
に代入しましょう.
out = new PrintWriter(System.out);
out
を return
してください.close
メソッドを用意しましょう.引数,返り値はありません.
out
に値が代入されていれば(null
でなければ),close
してください.System.out.printf
を呼び出していたところを,Arguments
の実体に対して,writer
メソッドを呼び出してください.
System.out.println
-> arguments.writer().println
arguments.close()
を呼び出して出力ストリームを閉じてください.Arguments6.java
のフィールドのみ4つ以上になっても構いません.