paiza プログラミング

[Ruby]paiza Bランクレベルアップメニュー 占い (paizaランク C 相当)の解説

B-lvup_占い

こんにちは!じゃいごテックのあつしです。

今回は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級までのほとんどの問題が解けると思います。
あとは文章問題への慣れだと思うので、どんどん問題をこなしていきましょう!



【PR】アルゴリズム学習でお世話になった本


アルゴリズム関連の技術書は大抵C/C++で書かれていますが、ある程度プログラムが出来れば、処理の流れは理解することが出来ます。






通称: 螺旋本。C++で解説されています。AOJ(Aizu Online Judge)を運営している会津大学の渡辺准教授が書いた本です。データ構造や計算量の内容から丁寧に書いてありますのでアルゴリズム学習の最初の参考書としてオススメです。







通称: 蟻本。C++で解説されています。競技プログラミング中級者の定番書と言われていて、競技プログラミングで利用できる色々なアルゴリズムを学ぶことが出来ます。かなり高度な内容も含まれているので1冊分を完全に理解するのにはかなりの時間がかかりそうですが、手元に置いて何度も読み返しています。







通称: チーター本。C#, C++, JAVAでTopcoderの問題を解説しています。初心者~中級者向けに書かれているので解説が非常に丁寧です。







Python3でアルゴリズムを解説している本です。講義スタイルの本で、図やフローチャートを使ってアルゴリズムとデータ構造についてしっかりと説明されています。代わりにコードは少なめです。Pythonコードが読めなくても十分理解できると思います。


-paiza, プログラミング
-, , , , ,

© 2024 じゃいごテック