こんにちは!じゃいごテックのあつしです。
今回はpaiza Cランクレベルアップメニュー から標準入出力という問題を解説していきたいと思います。
この問題集は標準入出力に関する6個のSTEP問題(D級)とFINAL問題(C級)で構成されていて、STEP問題を解いて行けばFINAL問題も解けるはず!となっています。
STEP問題を解いてみる
STEP問題は標準入力の基本問題です。
簡単な解説は付けていますが、難しいと感じたら下記の記事も参考にしてみて下さい。
STEP1: 単純な入出力 (paizaランク D 相当)
STEP1 は標準入力からの文字列をそのまま出力する問題です。
解答例
<<EOS 入力例1 paiza 出力例1 paiza 入力例2 Paiza21 出力例2 paiza21 EOS # [解答例1] puts gets # [解答例2] chomp を付けてもok puts gets.chomp
getsメソッド で標準入力から文字列を受け取り、putsメソッド でそのまま標準出力に渡します。
putsメソッド は末尾に改行が無い場合、自動で改行を追加して出力、末尾に改行がある場合はそのまま出力しますので、 chompメソッド は有っても無くても構いません。
STEP2: 複数行にわたる出力 (paizaランク D 相当)
STEP2 は標準入力で整数 n が与えられ、 n 回、指定文字列 "paiza" を改行区切りで出力する問題です。
解答例
<<EOS
入力例1
n
出力例1
paiza
paiza
入力例2
5
出力例2
paiza
paiza
paiza
paiza
paiza
EOS
# [解答例1]
puts "paiza\n" * gets.to_i
# [解答例2]
gets.to_i.times { puts "paiza" }
この問題のポイントは標準入力の文字列を to_iメソッド で整数にして処理を行うことと、改行区切りで複数行の出力を行うことです。解答例1では文字列の連結を使い、解答例2では繰り返し処理を使っています。
STEP3: 複数行にわたる入力 (paizaランク D 相当)
STEP3 は標準入力から1行目でデータ件数 nを受け取り、続くn行のデータを受け取り、そのまま出力する問題です。
解答例
<<EOS
入力例1
2
1
2
出力例1
1
2
入力例2
3
10
5
39
出力例2
10
5
39
EOS
# [解答例1]
n = gets.to_i
n.times { puts gets }
# [解答例2]
get.to_i.times { puts gets }
この問題のポイントは、標準入力の文字列を to_iメソッド で整数にして処理を行うことと、繰り返し処理で入力・出力を行うことです。
STEP4: 入力の配列による保持 (paizaランク D 相当)
STEP4 は標準入力から1行目でデータ件数 nを受け取り、続くn行のデータを受け取って整数に変換し、受け取った値の中で最大の値を表示する問題です。
解答例
<<EOS
入力例1
2
4
7
出力例1
7
入力例2
3
20
19
2
出力例2
20
EOS
# [解答例1]
ary = []
max_num = 0
gets.to_i.times do
num = gets.to_i
max_num = num if max_num < num
ary.push(num)
end
puts max_num
# [解答例2]
ary = gets.to_i.times.map { gets.to_i }
puts ary.max
解答例1は現時点での最大値 max_numと受け取った値 numを比較・上書きしながら最大値を探しつつ、配列 ary にデータを追加しています。受け取る値は 1から50の間の整数であることがわかっているので、max_num を 0 で初期化することによって1回目の比較で必ず上書きされます。
解答例2は一旦全てのデータを配列に格納した後、maxメソッドで最大値を検索して出力しています。
STEP5: 半角スペース区切りでの出力 (paizaランク D 相当)
STEP5 は標準入力で整数 n が与えられ、 n 個の指定文字列 "paiza" をスペース区切りで出力する問題です。
解答例
<<EOS
入力例1
2
出力例1
paiza paiza
入力例2
3
出力例2
paiza paiza paiza
EOS
# [解答例1]
result = ""
(1..gets.to_i).each do |count|
result << "paiza"
break if count == n
result << " "
end
puts result
# [解答例2]
puts Array.new(gets.to_i, "paiza").join(" ")
解答例1: n回の繰り返し処理を行い、空文字で初期化した result に "paiza" を連結します。n-1回目までは半角スペースを連結していますが、n回目(最後)は break で繰り返し処理を抜けるので、半角スペースを連結しません。
解答例2: サイズが n で、初期値が "paiza" の配列を生成し、joinメソッドで半角スペース区切りの文字列を生成して表示しています。
STEP6: 改行区切りでの出力 (paizaランク D 相当)
STEP6 は1行目に要素数 n、2行目にn個の整数が半角スペースで与えられ、n個の整数を改行区切りで出力する問題です。
<<EOS 入力例1 2 1 5 出力例1 1 5 入力例2 3 4 30 12 出力例2 4 30 12 EOS # [解答例1] gets gets.split.each do |value| puts value end # [解答例2] gets puts gets.split
解答例1: 1行目の入力を捨てて、2行目の入力を半角スペースで分割した配列の各要素を出力しています。
解答例2: 1行目の入力を捨てて、2行目の入力を半角スペースで分割した配列に対してputsメソッドで出力しています。
配列に対してputsメソッドを使うと、各要素を改行区切りで出力してくれます。
標準入出力 (paizaランク C 相当) を解いてみる
※ paiza Cランクレベルアップメニューより
問題
毎年 5 月 1 日に、自分が運営している会社の社員一覧表を作成しています。表は年度ごとに更新され、社員の名前と年齢が載っています。
ところで、会社のメンバーは昨年度から全く変わらず、社員の誕生日は全員 7 月 7 日だったので、前年度の一覧表の年齢欄をそれぞれ +1 するだけで今年度の表が作れることにパイザ君は気づきました。
昨年度の一覧表が与えられるので、今年度の一覧表を出力してください。
入力される値
入力は以下のフォーマットで与えられます。
N s_1 a_1 ... s_N a_N
1 行目には社員の数を表す整数 N が与えられ、2 行目 〜 (N + 1) 行目の各行では、社員の名前を表す文字列 s_i とその社員の昨年度の年齢を表す整数 a_i が半角スペース区切りで与えられます(1 ≤ i ≤ N)。
入力値最終行の末尾に改行が1つ入ります。
期待する出力
入力された通りの順番で、社員 s_i の名前と、その社員の今年度の年齢を半角スペース区切りでN行出力してください。
s_1 (a_1 + 1) ... s_N (a_N + 1)
末尾に改行を入れ、余計な文字、空行を含んではいけません。
条件
すべてのテストケースにおいて、以下の条件をみたします。
- 1 ≤ N ≤ 50
- s_i(1 ≤ i ≤ N)は 1 文字以上 10 文字以下の文字列
- s_i(1 ≤ i ≤ N)の各文字は英小文字または英大文字または数字
- 18 ≤ a_i ≤ 120(1 ≤ i ≤ N)
- 入力例1
- 1
Yamada 30
- 出力例1
- Yamada 31
- 入力例2
- 3
Tanaka 18
Sato 50
Suzuki 120
- 出力例2
- Tanaka 19
Sato 51
Suzuki 121
攻略ポイント
ポイント
- 標準入力からの複数行データ取得
- 文字列の分割、連結
- 文字列型 ⇔ 整数型 の型変換
デバッグを楽にするためにメソッドを作成します。小問題解説で紹介した記事プラス下記の記事も参考にしてみて下さい。
問題を解く流れ
入出力例をコピペしてヒアドキュメントで変数に代入し、データを確認します。正しく受け取れていれば確認用コードは削除します。
INPUT1 = <<~"EOS" 1 Yamada 30 EOS OUTPUT1 = <<~"EOS" Yamada 31 EOS INPUT2 = <<~"EOS" 3 Tanaka 18 Sato 50 Suzuki 120 EOS OUTPUT2 = <<~"EOS" Tanaka 19 Sato 51 Suzuki 121 EOS # 確認用コード p INPUT1 # > "1\nYamada 30\n" p INPUT2 # > "3\nTanaka 18\nSato 50\nSuzuki 120\n"
続いて問題を解くメソッド( solve メソッドとします)を変数の下に定義します。
まず、入力データを受け取る処理を書きます。
入力された文字列を改行で分割し、1行目は使わないので _ に代入、2行目以降を配列 members に代入します。
def solve(input_lines)
# input_lines を改行区切りで分割する
# 1行目を _ に代入(使わないので捨てる)
# 2行目以降を members 配列に格納
_, *members = input_lines.split("\n")
# 確認用コード
members
end
# 確認用コード
p solve(INPUT1)
# > ["Yamada 30"]
p solve(INPUT2)
# > ["Tanaka 18", "Sato 50", "Suzuki 120"]
名前と年齢が半角で連結された文字列データが正しく受け取れていれば、次に solve メソッドに年齢を +1 する処理を追加していきます。
membersの先頭から次々と要素を取り出して、半角スペースで分割して名前 nameと年齢 ageに分けます。年齢 ageを整数型に変換して +1 します。名前 nameと年齢 ageを半角スペース区切りの文字列に変換します。map!メソッドを使ってそれぞれの要素を処理した結果で members を上書きします。
def solve(input_lines)
# input_lines を改行区切りで分割する
# 1行目を _ に代入(使わないので捨てる)
# 2行目以降を members 配列に格納
_, *members = input_lines.split("\n")
members.map! do |member|
name, age = member.split
"#{name} #{age.to_i + 1}"
end
# 確認用コード
members
end
# 確認用コード
p solve(INPUT1)
# > ["Yamada 31"]
p solve(INPUT1) == OUTPUT1
# > false
p solve(INPUT2)
# > ["Tanaka 19", "Sato 51", "Suzuki 121"]
p solve(INPUT2) == OUTPUT2
# > false
各社員の年齢が +1 されていれば、あとは出力を整えれば完成です。
p solve(INPUT1) を puts solve(STDIN.read) に変更すれば正解となりますが、p solve(INPUT1) == OUTPUT1 -> true を確認するために、結果を改行区切りの文字列に変換して、末尾にも改行を加えます。
def solve(input_lines)
# input_lines を改行区切りで分割する
# 1行目を _ に代入(使わないので捨てる)
# 2行目以降を members 配列に格納
_, *members = input_lines.split("\n")
members.map! do |member|
name, age = member.split
"#{name} #{age.to_i + 1}"
end
# members を改行区切りにして末尾にも改行を加えた文字列に変換する
members.join("\n") << "\n"
end
# 確認用コード
p solve(INPUT1)
# > "Yamada 31\n"
p solve(INPUT1) == OUTPUT1
# > true
p solve(INPUT2)
# > "Tanaka 19\nSato 51\nSuzuki 121\n"
p solve(INPUT2) == OUTPUT2
# > true
確認用コードを標準入力からのデータ受け取りに変更して、動作確認をしたら提出します。
複数行のデータ受け取りなので STDIN.read を使います。(入力終了は Ctrl+D 又は Ctrl+Z)
解答コード
def solve(input_lines)
# input_lines を改行区切りで分割する
# 1行目を _ に代入(使わないので捨てる)
# 2行目以降を members 配列に格納
_, *members = input_lines.split("\n")
members.map! do |member|
name, age = member.split
"#{name} #{age.to_i + 1}"
end
# members を改行区切りにして末尾にも改行を加えた文字列に変換する
members.join("\n") << "\n"
end
puts solve(STDIN.read)
今回のまとめ
この問題集を通して以下の操作を覚えることが出来ました。
- 複数行のデータ受け取り
- 繰り返し処理
- 文字列の分割、結合、繰り返し
- 文字列型⇔整数型の変換

標準入出力は競プロに挑戦するための基本になります。
色々なパターンの入出力に挑戦して、引き出しを増やしていきましょう!