クラスを理解するための例題(1)
世の中にある多くの課題は、必ずしもクラスを作成、使用しなくては解決できないということではありません。しかし、適切なクラスを設計し、用いることでよりわかりやすく、整理されたコードを記述することができるようになります。
ここからは、具体的な問題を例に、クラスのメリットや具体的な書き方を解説します。
例題1:必ずしもクラスを使う必要のないケース
例えば以下のような要件について考えてみましょう。
例題1
クラスの学級委員であるpaiza君は、クラスのみんなに次のような形式でアカウントの情報を送ってもらうよう依頼しました。
名前 年齢 誕生日 出身地
送ってもらったデータを使いやすいように整理したいと思った paiza 君はクラス全員分のデータを次の形式でまとめることにしました。
User{
nickname : 名前
old : 年齢
birth : 誕生日
state : 出身地
}
クラスメートの情報が与えられるので、それらを以上の形式でまとめたものを出力してください。
入力される値は以下のように与えられます。
入力される値 N n_1 o_1 b_1 s_1 ... n_N o_N b_N s_N
- 1行目では、paiza君のクラスの人数Nが与えられます。
-
続く
N行のうちi行目(1 ≦ i ≦ N)では、i番の生徒の名前・年齢・誕生日・出身地を表す整数・文字列n_i ,o_i ,b_i , s_iが順に半角スペース区切りで与えられます。
入力値の条件は以下となっています。
-
1 ≦ N ≦ 10 -
n_i , s_i (1 ≦ i ≦ N)は1文字以上20文字以下の文字列 -
b_i (1 ≦ i ≦ N)はMM/DD形式の文字列(例:1月2日→01/02、12月31日→12/31) -
1 ≦ o_i ≦ 100
期待される出力は以下のものです。
User{
nickname : n_1
old : o_1
birth : b_1
state : s_1
}
User{
nickname : n_2
old : o_2
birth : b_2
state : s_2
}
...
User{
nickname : n_N
old : o_N
birth : b_N
state : s_N
}
番号が若い順に各クラスメートの情報を以上の形式で出力してください。
この問題について、まずはそのまま記述してみましょう。言語はJavaを使用します。
import java.util.*;
import java.util.stream.*;
public class Main {
public static void main(String[] args) {
var sc = new Scanner(System.in);
IntStream
.range(0, sc.nextInt())
.mapToObj(i ->
"""
User{
nickname : $nickname
old : $old
birth : $birth
state : $state
}"""
.replace("$nickname", sc.next())
.replace("$old", sc.next())
.replace("$birth", sc.next())
.replace("$state", sc.next()))
.forEach(System.out::println);
}
}
さまざまな書き方があると思いますが、大方このようなコードになると思います。受け取ったデータを整形してただ出力せよ、という要件なので、これで特に問題はありませんね。
例題2:必ずしもクラスを使う必要のないケース
続いて次のような要件について考えます。
例題2
クラスの学級委員であるpaiza君は、クラスのみんなに次のような形式でアカウントの情報を送ってもらうよう依頼しました。
名前 年齢 誕生日 出身地
年齢ごとの生徒の名簿を作る仕事を任されたpaiza君はクラスメイトのうち、決まった年齢の生徒を取り出したいと考えました。
取り出したい生徒の年齢が与えられるので、その年齢の生徒の名前を出力してください。
入力値は以下のように与えられます。
N n_1 o_1 b_1 s_1 ... n_N o_N b_N s_N K
-
1行目では、paiza君のクラスの人数
Nが与えられます。 -
続く
N行のうちi行目(1 ≦ i ≦ N)では、i番の生徒の名前・年齢・誕生日・出身地を表す整数・文字列n_i ,o_i ,b_i , s_iが順に半角スペース区切りで与えられます。 -
N + 2行目では、検索したい生徒の年齢Kが与えられます。
また条件は以下のようになっています。
-
1 ≦ N ≦ 10 -
n_i , s_i (1 ≦ i ≦ N)は1文字以上20文字以下の文字列 -
b_i (1 ≦ i ≦ N)はMM/DD形式の文字列(例:1月2日→01/02、12月31日→12/31) -
1 ≦ o_i , K ≦ 100 -
年齢が
Kであるような生徒はクラスに1人
期待される出力は以下のものです。
年齢がKである生徒の名前を1行で出力してください。
この場合はどうでしょうか。
検索したい生徒の年齢が最後に与えられるということもあり、一旦生徒のデータは保存しておかなければならなそうです。これもまたさまざまな方法があると思いますが、例えば各属性ごとにまとめるリストを用意しておき、そのインデックスで生徒を識別するようにしてみましょうか。
import java.util.*;
import java.util.stream.*;
public class Main {
public static void main(String[] args) {
var sc = new Scanner(System.in);
var name = new ArrayList<String>();
var old = new ArrayList<Integer>();
var birth = new ArrayList<String>();
var state = new ArrayList<String>();
IntStream
.range(0, sc.nextInt())
.forEach(i -> {
name.add(sc.next());
old.add(sc.nextInt());
birth.add(sc.next());
state.add(sc.next());
});
System.out.println(name.get(old.indexOf(sc.nextInt())));
}
}
このようになります。各リストのインデックスが同一の要素は同じ生徒の情報を表すことになるため、年齢のリストから対象となる年齢のインデックスを調べ、その値を使って名前を取得しています。これも大丈夫そうです。
