こんにちは!じゃいごテックのあつしです。
今回はpaiza Bランクレベルアップメニュー から文字と整数の組のソートという問題を解説します。
この問題集はデータのソートに関する3個のSTEP問題(D級)とFINAL問題(C級)で構成されていて、STEP問題を解いて行けばFINAL問題も解けるはず!となっています。
STEP問題を解いてみる
STEP問題は基本的なメソッドについての問題です。
簡単な解説は付けていますが、難しいと感じたら下記の記事も参考にしてみて下さい。
※過去に出題された小問題が出てくることがありますが、チケットに余裕があれば復習のつもりで取り組んでみましょう。
STEP1: インクリメント (paizaランク D 相当)
STEP1 は受け取った整数をインクリメント(+1)して出力する問題です。
解答例
<< EOS 入力例1 -10 出力例1 -9 入力例2 0 出力例2 1 入力例3 1 出力例3 2 EOS n = gets.to_i puts n + 1
解答例: 標準入力で受けとった文字列を整数型に変換、+1 して出力しています。
STEP2: 数字のみの出力 (paizaランク D 相当)
STEP2 は複数の半角スペース区切りの文字と整数のペアが渡され、整数だけを先頭から順に出力する問題です。
解答例
<<"EOS" 4 S 1 F 2 E 5 Y 6 出力例1 1 2 5 6 入力例2 3 S -3 G -5 R -35 出力例2 -3 -5 -35 入力例3 6 A 12 E 42 G -8 R -7 Y 56 E 22 出力例3 12 42 -8 -7 56 22 EOS # [解答例1] n = gets.to_i ary = [] n.times do s, d = gets.split ary.push([s, d.to_i]) end ary.each do |s, d| puts d end # [解答例2] n = gets.to_i hash = {} n.times do s, d = gets.split hash[s] = d.to_i end puts hash.values
解答例1: 文字と数字のペアを配列で受け取って、二次元配列の先頭から順に2番目の要素を出力しています。
解答例2: 文字と数字のペアを配列で受け取り、文字をキー、数字を値にしたハッシュに格納して、valuesメソッド
で値の配列を取得して出力しています。
STEP3: 昇順ソート出力 (paizaランク D 相当)
STEP2 は半角スペース区切りの整数を受け取り、昇順に並べ替えて出力する問題です。
解答例
<<"EOS" 入力例1 8 90 777 8888 121 333 4 29 2 出力例1 2 4 29 90 121 333 777 8888 入力例2 10 10 9 8 7 6 5 4 3 2 1 出力例2 1 2 3 4 5 6 7 8 9 10 入力例3 1 3 出力例3 3 EOS # [解答例1] n = gets.to_i ary = gets.split.map(&:to_i) sorted_ary = [] ary.each do |t_n| inserted = false sorted_ary.each_with_index do |a_n, idx| if t_n < a_n sorted_ary.insert(idx, t_n) inserted = true break end end sorted_ary << t_n if not inserted end puts sorted_ary # [解答例2] n = gets.to_i ary = gets.split.map(&:to_i) puts ary.sort
解答例1: 配列ary
の先頭から順に値を取り出し、sorted_aryの値と比較して昇順になるようにsorted_aryに挿入しています。
※ 解説のために自前でソートを実装しましたが、通常はsortメソッドを使った方が楽なうえに処理も早いです。
解答例2: sortメソッド
で昇順の配列を生成して出力しています。
文字と整数の組のソート (paizaランク C 相当)を解いてみる
※ paiza Bランクレベルアップメニューより
問題
1行目に行数を表す整数 n、続く n 行の各行で「文字」と「整数」の組が空白区切りで入力されます。
n 個の組を、「整数」の値で昇順に並べ変え、「文字」を出力してください。
入力される値
入力は以下のフォーマットで与えられます。
n
S_1 D_1
S_2 D_2
...
S_i D_i
...
S_n D_n
S_i は「文字」で、D_i は「整数」です。
入力される文字 S_i は、同じ文字が複数入力されることはなく、整数 D_i も同様です。
入力値最終行の末尾に改行が1つ入ります。
期待する出力
n 個の組を、「整数」の値で昇順に並べ変え、「文字列」を1行ずつ出力してください。
条件
すべてのテストケースにおいて、以下の条件をみたします。
- 1 ≦ n ≦ 100
- -10,000 ≦ D_i ≦ 10,000
- S_iは半角英文字1文字
- iとjが異なるなら、D_iとD_jは異なる
- iとjが異なるなら、S_iとS_jは異なる
- 入力例1
- 2
A 1
B 2
- 出力例1
- A
B
- 入力例2
- 3
G 0
S 3
E -2
- 出力例2
- E
G
S
- 入力例3
- 5
H -2
R 0
W -5
A -1
E -20
- 出力例3
- E
W
H
A
R
攻略ポイント
ポイント
sort_byメソッド
で二次元配列(又はハッシュ)の指定要素で昇順ソートを行う- 二次元配列(又はハッシュ)の指定された要素だけを出力する
デバッグを楽にするためにメソッドを作成します。メソッドについては下記の記事も参考にしてみて下さい。
問題を解く流れ
入出力例をコピペしてヒアドキュメントで変数に代入し、データを確認します。正しく受け取れていれば確認用コードは削除します。
INPUT1 = <<~"EOS" 2 A 1 B 2 EOS OUTPUT1 = <<~"EOS" A B EOS INPUT2 = <<~"EOS" 3 G 0 S 3 E -2 EOS OUTPUT2 = <<~"EOS" E G S EOS INPUT3 = <<~"EOS" 5 H -2 R 0 W -5 A -1 E -20 EOS OUTPUT3 = <<~"EOS" E W H A R EOS # 確認用コード p INPUT1 # > "2\nA 1\nB 2\n" p OUTPUT1 # > "A\nB\n" p INPUT2 # > "3\nG 0\nS 3\nE -2\n" p OUTPUT2 # > "E\nG\nS\n" p INPUT3 # > "5\nH -2\nR 0\nW -5\nA -1\nE -20\n" p OUTPUT3 # > "E\nW\nH\nA\nR\n"
続いて問題を解くメソッド( solve
メソッドとします)を変数の下に定義します。
まず、入力データを受け取る処理を書きます。
def solve(input_lines) # 入力データ受け取り input_lines = input_lines.split("\n") n = input_lines.shift.to_i # 確認用コード [n, input_lines] end # 確認用コード p solve(INPUT1) # > [2, ["A 1", "B 2"]] p solve(INPUT2) # > [3, ["G 0", "S 3", "E -2"]] p solve(INPUT3) # > [5, ["H -2", "R 0", "W -5", "A -1", "E -20"]]
データが正しく受け取れていれば、solve
メソッドに文字と数字のペアを数字の昇順でソートする処理を追加していきます。
- 文字と整数のペアを配列に格納する(二次元配列になる)
- 2番目の要素(整数)で昇順に並び替えた配列を生成する
def solve(input_lines) # 入力データ受け取り input_lines = input_lines.split("\n") n = input_lines.shift.to_i # 文字と整数のペアを配列に格納する ary = input_lines.map do |line| s, d = line.split [s, d.to_i] end # 2番目の要素(整数)で昇順に並び替えた配列を生成する sorted_ary = ary.sort_by { |x| x[1] } # 確認用コード sorted_ary.map { |x| x[0] } end # 確認用コード p solve(INPUT1) # > ["A", "B"] p solve(INPUT1) == OUTPUT1 # > false p solve(INPUT2) # > ["E", "G", "S"] p solve(INPUT2) == OUTPUT2 # > false p solve(INPUT3) # > ["E", "W", "H", "A", "R"] p solve(INPUT3) == OUTPUT3 # > false
あとは出力形式を整えれば完成です。
p solve(INPUT1)
を puts solve(STDIN.read)
に変更すれば正解となりますが、p solve(INPUT1) == OUTPUT1 -> true
を確認するために、結果を改行区切りの文字列に変換して、末尾にも改行を加えます。
def solve(input_lines) # 入力データ受け取り input_lines = input_lines.split("\n") n = input_lines.shift.to_i # 文字と整数のペアを配列に格納する ary = input_lines.map do |line| s, d = line.split [s, d.to_i] end # 2番目の要素(整数)で昇順に並び替えた配列を生成する sorted_ary = ary.sort_by { |x| x[1] } # 文字列に変換して末尾に改行を追加する sorted_ary.map { |x| x[0] }.join("\n") << "\n" end # 確認用コード p solve(INPUT1) # > "A\nB\n" p solve(INPUT1) == OUTPUT1 # > true p solve(INPUT2) # > "E\nG\nS\n" p solve(INPUT2) == OUTPUT2 # > true p solve(INPUT3) # > "E\nW\nH\nA\nR\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 # 文字と整数のペアを配列に格納する ary = input_lines.map do |line| s, d = line.split [s, d.to_i] end # 2番目の要素(整数)で昇順に並び替えた配列を生成する sorted_ary = ary.sort_by { |x| x[1] } # 文字列に変換して末尾に改行を追加する sorted_ary.map { |x| x[0] }.join("\n") << "\n" end puts solve(STDIN.read)
他の解答例
- 数値で昇順ソートした配列をハッシュに変換し、
keysメソッド
で文字の配列を取り出す。
def solve(input_lines) # 入力データ受け取り n, *lines = input_lines.split("\n") # 文字と整数のペアを配列に格納する ary = lines.map do |line| s, d = line.split [s, d.to_i] end # 整数で昇順ソートしてハッシュに変換する sorted_hash = ary.sort_by { |x| x[1] }.to_h # ハッシュのキーの配列を改行区切りで出力する sorted_hash.keys.join("\n") << "\n" end puts solve(STDIN.read)
今回のまとめ
sort_byメソッド
を使って二次元配列(又はハッシュ)の指定された要素で昇順ソートを行いました- 二次元配列は
mapメソッド
、ハッシュはkeysメソッド
で指定された要素だけの配列を取り出しました
(ハッシュの値の配列はvaluesメソッド
で取り出すことが出来る)
データの種類や処理内容によって二次元配列とハッシュを使い分けられると便利ですね!