こんにちは!じゃいごテックのあつしです。
今回はpaiza Bランクレベルアップメニュー から占いという問題を解説します。
この問題集はハッシュ(連想配列)に関する5個のSTEP問題(D~C級)とFINAL問題(C級)で構成されていて、STEP問題を解いて行けばFINAL問題も解けるはず!となっています。
STEP問題を解いてみる
STEP問題はハッシュの基本的な使い方についての問題です。
簡単な解説は付けていますが、難しいと感じたら下記の記事も参考にしてみて下さい。
標準入力・標準出力
配列
ハッシュ(連想配列)
繰り返し
メソッド
STEP1: 連想配列(辞書)を使う (paizaランク D 相当)
STEP1 は指定された名前と血液型のペアをハッシュに格納した後、半角スペースで連結して表示する問題です。
解答例
users = { "Kyoko" => "B", "Rio" => "O", "Tsubame" => "AB", "KurodaSensei" => "A", "NekoSensei" => "A", } # [解答例1] users.each { |key, val| puts "#{key} #{val}" } # [解答例2] users.each { |user| puts user.join(" ") }
解答例1 : eachメソッド
でハッシュの先頭から順にキーと値を個別に取り出して、式展開で半角スペースで連結した文字列を作って出力しています。
解答例2 : eachメソッド
でハッシュの先頭から順にキーと値の配列で取り出して、joinメソッド
で半角スペースで連結した文字列を作って出力しています。
STEP2: ユーザーの血液型のデータ処理 (paizaランク C 相当)
STEP2 はn行
の名前と血液型のペアをハッシュに格納し、名前と血液型を半角スペースで連結して出力する問題です。
解答例
<<~"EOS" 入力例1 5 Kyoko B Rio O Tsubame AB KurodaSensei A NekoSensei A 出力例1 Kyoko B Rio O Tsubame AB KurodaSensei A NekoSensei A 入力例2 5 shishiza O yagiza O otomeza AB mizugameza B futagoza A 出力例2 shishiza O yagiza O otomeza AB mizugameza B futagoza A 入力例3 3 AAA A BBB B CCC A 出力例3 AAA A BBB B CCC A EOS # [解答例1] n = gets.to_i users = {} n.times do name, blood_type = gets.split users[name] = blood_type end users.each { |key, val| puts "#{key} #{val}" } # [解答例2] n = gets.to_i users = n.times.map { gets.split }.to_h users.each { |user| puts user.join(" ") }
解答例1 : timesメソッド
で1件ごとに名前と血液型のペアをハッシュに追加した後、eachメソッド
でハッシュの先頭から順にキーと値を個別に取り出して、式展開で半角スペースで連結した文字列を作って出力しています。
解答例2 : 名前と血液型のペアの配列で配列(二次元配列)に格納してto_hメソッド
でハッシュに変換した後、eachメソッド
でハッシュの先頭から順にキーと値の配列で取り出して、joinメソッド
で半角スペースで連結した文字列を作って出力しています。
STEP3: 1人の血液型 (paizaランク C 相当)
STEP3 はn行
の名前と血液型のペアをハッシュに格納し、指定された名前と血液型を半角スペースで連結して出力する問題です。
解答例
<<"EOS" 入力例1 Kyoko 5 Kyoko B Rio O Tsubame AB KurodaSensei A NekoSensei A 出力例1 Kyoko B 入力例2 otomeza 5 shishiza O yagiza O otomeza AB mizugameza B futagoza A 出力例2 otomeza AB 入力例3 EEE 5 AAA A BBB B CCC A DDD AB EEE O 出力例3 EEE O EOS s = gets.chomp n = gets.to_i users = {} n.times do name, blood_type = gets.split users[name] = blood_type end puts "#{s} #{users[s]}"
解答例: ハッシュ[キー(名前)]
で値(血液型)を参照して、式展開で半角スペース区切りの文字列を出力しています。
STEP4: 1つの血液型を占う (paizaランク C 相当)
STEP4 は4種類の血液型(A, B, O, AB)と占い結果のペアをハッシュに格納し、指定された血液型の占い結果を出力する問題です。
解答例
<<"EOS" 入力例1 A 4 A Good B VeryGood O Yavai AB VeryYavai 出力例1 Good 入力例2 B 4 A Good B VeryGood O Yavai AB VeryYavai 出力例2 VeryGood 入力例3 O 4 A Good B VeryGood O Yavai AB VeryYavai 出力例3 Yavai EOS t = gets.chomp m = gets.to_i fortune_telling = {} m.times do blood_type, fortune = gets.split fortune_telling[blood_type] = fortune end puts fortune_telling[t]
解答例: ハッシュ[キー(血液型)]で値(占い結果)を参照して出力しています。
STEP5: 1人の占い結果 (paizaランク C 相当)
STEP5 はn行
の名前とタイプ(血液型や星座)のペアと、m行のタイプ(血液型や星座)と占い結果のペアをそれぞれハッシュに格納し、指定された名前の占い結果を出力する問題です。
解答例
<<"EOS" 入力例1 Kyoko 5 Kyoko B Rio O Tsubame AB KurodaSensei A NekoSensei A 4 A red B green O blue AB yellow 出力例1 green 入力例2 Rio 5 Kyoko shishiza Rio futagoza Tsubame otomeza KurodaSensei yagiza NekoSensei mizugameza 5 shishiza the_first_person yagiza the_second_person otomeza the_first_cat mizugameza the_first_dog futagoza NekoSensei 出力例2 NekoSensei 入力例3 CCC 3 AAA aaa111 BBB bbb222 CCC ccc333 5 aaa111 zzz bbb222 yyy ccc333 xxx ddd444 www eee555 vvv 出力例3 xxx EOS # [解答例1] u = gets.chomp n = gets.to_i users = {} n.times do name, blood_type = gets.split users[name] = blood_type end m = gets.to_i fortune_telling = {} m.times do blood_type, fortune = gets.split fortune_telling[blood_type] = fortune end u_blood_type = users[u] puts fortune_telling[u_blood_type] # [解答例2] u = gets.chomp n = gets.to_i users = n.times.map { gets.split }.to_h m = gets.to_i fortune_telling = m.times.map { gets.split }.to_h puts fortune_telling[users[u]]
解答例1 : timesメソッド
で1件ごとに名前とタイプのペアと、タイプと占い結果のペアをハッシュに追加した後、u_blood_type = users[u]
で占うタイプを受け取り、fortune_telling[u_blood_type]
で占い結果を参照して出力しています。
解答例2 : 名前とタイプのペアとタイプと占い結果のペアの二次元配列をそれぞれto_hメソッド
でハッシュに変換した後、fortune_telling[users[u]]
で占い結果を参照して出力しています。
占い (paizaランク C 相当)を解いてみる
※ paiza Bランクレベルアップメニューより
問題
次のような占いプログラムを作成してください。
「ユーザー」と「ユーザーに対応する血液型」、「血液型」と「血液型に対応する占い結果」が与えられます。
それぞれのユーザーに対応する占い結果を表示してください。
入力例の1つ目は、ユーザーの血液型についてのラッキーカラーの占いです。
入力例の2つ目は、ユーザーの星座についてのラッキーパーソンの占いになっています。
「血液型」として「星座」などのさまざまな文字列を利用できるようにすることで、他の占いにも対応する必要があることに注意してください。
入力される値
入力は以下のフォーマットで与えられます。
n
(ユーザー_1) (ユーザー_1の血液型)
(ユーザー_2) (ユーザー_2の血液型)
(ユーザー_3) (ユーザー_3の血液型)
...
(ユーザー_i) (ユーザー_iの血液型)
...
(ユーザー_n) (ユーザー_nの血液型)
m
(血液型_1) (血液型_1の占い結果)
(血液型_2) (血液型_2の占い結果)
(血液型_3) (血液型_3の占い結果)
...
(血液型_j) (血液型_jの占い結果)
..
(血液型_m) (血液型_mの占い結果)
入力値最終行の末尾に改行が1つ入ります。
期待する出力
1から n までの各ユーザーについて順に、ユーザーとその占い結果を半角スペース区切りで出力してください。
最後は改行し、余計な文字、空行を含んではいけません。
条件
すべてのテストケースにおいて、以下の条件をみたします。
- 1 ≦ n ≦100
- 1 ≦ m ≦100
- (ユーザー_i)は、半角英数字からなる1から20文字までの文字列
- (血液型_j)は、半角英数字からなる1から20文字までの文字列
- (血液型_jの占い結果)は、半角英数字からなる1から20文字までの文字列
- (ユーザー_iの血液型)と等しい、(血液型_j)が必ず存在
- i ≠kのとき、(ユーザー_i)と(ユーザー_k)は異なる文字列
- j ≠kのとき、(血液型_j)と(血液型_k)は異なる文字列
- 入力例1
- 5
Kyoko B
Rio O
Tsubame AB
KurodaSensei A
NekoSensei A
4
A red
B green
O blue
AB yellow
- 出力例1
- Kyoko green
Rio blue
Tsubame yellow
KurodaSensei red
NekoSensei red
- 入力例2
- 5
Kyoko shishiza
Rio futagoza
Tsubame otomeza
KurodaSensei yagiza
NekoSensei mizugameza
5
shishiza the_first_person
yagiza the_second_person
otomeza the_first_cat
mizugameza the_first_dog
futagoza NekoSensei
- 出力例2
- Kyoko the_first_person
Rio NekoSensei
Tsubame the_first_cat
KurodaSensei the_second_person
NekoSensei the_first_dog
- 入力例3
- 3
AAA aaa111
BBB bbb222
CCC ccc333
5
aaa111 zzz
bbb222 yyy
ccc333 xxx
ddd444 www
eee555 vvv
- 出力例3
- AAA zzz
BBB yyy
CCC xxx
攻略ポイント
ポイント
- ハッシュを生成する
- ハッシュの値を次のハッシュのキーにして値を参照する
(名前でタイプを参照し、タイプで占い結果を参照する)
類似問題の解説記事
ほぼ同じ問題を図付きで解説しているので参考にどうぞ!
-
[Ruby]paiza Cランクレベルアップメニュー 辞書 (paizaランク C 相当)の解説
こんにちは!じゃいごテックのあつしです。 今回はpaiza Cランクレベルアップメニュー から辞書という問題を解説します。 この問題集は連想配列の使い方に関する3個のSTEP問題(C級)とFINAL問 ...
問題を解く流れ
入出力例をコピペしてヒアドキュメントで変数に代入し、データを確認します。正しく受け取れていれば確認用コードは削除します。(データが多い時はppメソッド
を使うといい感じに出力してくれます)
INPUT1 = <<~"EOS" 5 Kyoko B Rio O Tsubame AB KurodaSensei A NekoSensei A 4 A red B green O blue AB yellow EOS OUTPUT1 = <<~"EOS" Kyoko green Rio blue Tsubame yellow KurodaSensei red NekoSensei red EOS INPUT2 = <<~"EOS" 5 Kyoko shishiza Rio futagoza Tsubame otomeza KurodaSensei yagiza NekoSensei mizugameza 5 shishiza the_first_person yagiza the_second_person otomeza the_first_cat mizugameza the_first_dog futagoza NekoSensei EOS OUTPUT2 = <<~"EOS" Kyoko the_first_person Rio NekoSensei Tsubame the_first_cat KurodaSensei the_second_person NekoSensei the_first_dog EOS INPUT3 = <<~"EOS" 3 AAA aaa111 BBB bbb222 CCC ccc333 5 aaa111 zzz bbb222 yyy ccc333 xxx ddd444 www eee555 vvv EOS OUTPUT3 = <<~"EOS" AAA zzz BBB yyy CCC xxx EOS pp INPUT1 # > "5\n" + # > "Kyoko B\n" + # > "Rio O\n" + # > "Tsubame AB\n" + # > "KurodaSensei A\n" + # > "NekoSensei A\n" + # > "4\n" + # > "A red\n" + # > "B green\n" + # > "O blue\n" + # > "AB yellow\n" pp OUTPUT1 # > "Kyoko green\n" + # > "Rio blue\n" + # > "Tsubame yellow\n" + # > "KurodaSensei red\n" + # > "NekoSensei red\n" pp INPUT2 # > "5\n" + # > "Kyoko shishiza\n" + # > "Rio futagoza\n" + # > "Tsubame otomeza\n" + # > "KurodaSensei yagiza\n" + # > "NekoSensei mizugameza\n" + # > "5\n" + # > "shishiza the_first_person\n" + # > "yagiza the_second_person\n" + # > "otomeza the_first_cat\n" + # > "mizugameza the_first_dog\n" + # > "futagoza NekoSensei\n" pp OUTPUT2 # > "Kyoko the_first_person\n" + # > "Rio NekoSensei\n" + # > "Tsubame the_first_cat\n" + # > "KurodaSensei the_second_person\n" + # > "NekoSensei the_first_dog\n" pp INPUT3 # > "3\n" + # > "AAA aaa111\n" + # > "BBB bbb222\n" + # > "CCC ccc333\n" + # > "5\n" + # > "aaa111 zzz\n" + # > "bbb222 yyy\n" + # > "ccc333 xxx\n" + # > "ddd444 www\n" + # > "eee555 vvv\n" pp OUTPUT3 # > "AAA zzz\n" + "BBB yyy\n" + "CCC xxx\n"
続いて問題を解くメソッド( solve
メソッドとします)を変数の下に定義します。
まず、入力データを受け取る処理を書きます。
def solve(input_lines) # 入力データ受け取り input_lines = input_lines.split("\n") n = input_lines.shift.to_i users = {} input_lines.shift(n).each do |line| name, type = line.split users[name] = type end m = input_lines.shift.to_i fortune_telling = {} input_lines.shift(m).each do |line| type, fortune = line.split fortune_telling[type] = fortune end # 確認用コード [users, fortune_telling] end # 確認用コード pp solve(INPUT1) # > [{"Kyoko"=>"B", # > "Rio"=>"O", # > "Tsubame"=>"AB", # > "KurodaSensei"=>"A", # > "NekoSensei"=>"A"}, # > {"A"=>"red", "B"=>"green", "O"=>"blue", "AB"=>"yellow"}] pp solve(INPUT2) # > [{"Kyoko"=>"shishiza", # > "Rio"=>"futagoza", # > "Tsubame"=>"otomeza", # > "KurodaSensei"=>"yagiza", # > "NekoSensei"=>"mizugameza"}, # > {"shishiza"=>"the_first_person", # > "yagiza"=>"the_second_person", # > "otomeza"=>"the_first_cat", # > "mizugameza"=>"the_first_dog", # > "futagoza"=>"NekoSensei"}] pp solve(INPUT3) # > [{"AAA"=>"aaa111", "BBB"=>"bbb222", "CCC"=>"ccc333"}, # > {"aaa111"=>"zzz", # > "bbb222"=>"yyy", # > "ccc333"=>"xxx", # > "ddd444"=>"www", # > "eee555"=>"vvv"}]
データが正しく受け取れていれば、solve
メソッドに各ユーザーを順に占う処理を追加していきます。
def solve(input_lines) # 入力データ受け取り input_lines = input_lines.split("\n") n = input_lines.shift.to_i users = {} input_lines.shift(n).each do |line| name, type = line.split users[name] = type end m = input_lines.shift.to_i fortune_telling = {} input_lines.shift(m).each do |line| type, fortune = line.split fortune_telling[type] = fortune end # ユーザーを先頭から順に占う # 名前と結果を半角スペースで連結して配列に格納する result = [] users.each do |name, type| result.push("#{name} #{fortune_telling[type]}") end # 確認用コード result end # 確認用コード pp solve(INPUT1) # > ["Kyoko green", # > "Rio blue", # > "Tsubame yellow", # > "KurodaSensei red", # > "NekoSensei red"] p solve(INPUT1) == OUTPUT1 # > false pp solve(INPUT2) # > ["Kyoko the_first_person", # > "Rio NekoSensei", # > "Tsubame the_first_cat", # > "KurodaSensei the_second_person", # > "NekoSensei the_first_dog"] p solve(INPUT2) == OUTPUT2 # > false pp solve(INPUT3) # > ["AAA zzz", "BBB yyy", "CCC xxx"] p solve(INPUT3) == OUTPUT3 # > false
あとは出力形式を整えれば完成です。
p solve(INPUT1) == OUTPUT1 -> true
を確認するために、判定結果の末尾に改行を加えます。
def solve(input_lines) # 入力データ受け取り input_lines = input_lines.split("\n") n = input_lines.shift.to_i users = {} input_lines.shift(n).each do |line| name, type = line.split users[name] = type end m = input_lines.shift.to_i fortune_telling = {} input_lines.shift(m).each do |line| type, fortune = line.split fortune_telling[type] = fortune end # ユーザーを先頭から順に占う # 名前と結果を半角スペースで連結して配列に格納する result = [] users.each do |name, type| result.push("#{name} #{fortune_telling[type]}") end # 占い結果を改行で連結し末尾に改行を追加 result.join("\n") << "\n" end # 確認用コード pp solve(INPUT1) # > "Kyoko green\n" + # > "Rio blue\n" + # > "Tsubame yellow\n" + # > "KurodaSensei red\n" + # > "NekoSensei red\n" p solve(INPUT1) == OUTPUT1 # > true pp solve(INPUT2) # > "Kyoko the_first_person\n" + # > "Rio NekoSensei\n" + # > "Tsubame the_first_cat\n" + # > "KurodaSensei the_second_person\n" + # > "NekoSensei the_first_dog\n" p solve(INPUT2) == OUTPUT2 # > true pp solve(INPUT3) # > "AAA zzz\n" + "BBB yyy\n" + "CCC xxx\n" p solve(INPUT3) == OUTPUT3 # > true
入出力例での動作確認が出来ましたので、標準入力からのデータ受け取りに変更して、手動で動作確認をしたら提出します。
複数行のデータ受け取りなので STDIN.read
を使います。(入力終了は Ctrl+D
又は Ctrl+Z
)
解答コード
def solve(input_lines) # 入力データ受け取り input_lines = input_lines.split("\n") n = input_lines.shift.to_i users = {} input_lines.shift(n).each do |line| name, type = line.split users[name] = type end m = input_lines.shift.to_i fortune_telling = {} input_lines.shift(m).each do |line| type, fortune = line.split fortune_telling[type] = fortune end # ユーザーを先頭から順に占う # 名前と結果を半角スペースで連結して配列に格納する result = [] users.each do |name, type| result.push("#{name} #{fortune_telling[type]}") end # 占い結果を改行で連結し末尾に改行を追加 result.join("\n") << "\n" end puts solve(STDIN.read)
他の解答例
to_hメソッド
で二次元配列をハッシュに変換する
def solve(input_lines) # 入力データ受け取り input_lines = input_lines.split("\n") n = input_lines.shift.to_i users = input_lines.shift(n).map { |line| line.split }.to_h m = input_lines.shift.to_i fortune_telling = input_lines.shift(m).map { |line| line.split }.to_h # 名前と結果を半角スペースで連結して配列に格納する result = users.map { |name, type| "#{name} #{fortune_telling[type]}" } # 配列を改行で連結して末尾に改行を追加する result.join("\n") << "\n" end puts solve(STDIN.read)
今回のまとめ
今回はハッシュ(連想配列)を扱いました
- ハッシュを生成する(
hash = {}
,hash = {キー => 値}
) - ハッシュに要素を追加・変更する(
hash[キー] = 値
) - 要素がペアの二次元配列をハッシュに変換する(
二次元配列.to_h
)
ハッシュと配列を使いこなせばB級までのほとんどの問題が解けると思います。
あとは文章問題への慣れだと思うので、どんどん問題をこなしていきましょう!