INDEX
■はじめに
Rubyの基礎的な問題をたくさん解くことで基本的な考え方やメソッドの使い方を定着させたい。
基本的にはAtCoderというプログラミングコンテスト(競技プログラミング)の過去問を使う。(AtCoderは難易度が分かれており、難易度の低いA問題かB問題を解いていく)
(5/23時点の方針)
メソッドの切り分け方や値の受け渡しを練習するために、コード長の短さについては気にせずに書くことにする。
■問題
●出典
AtCoder Beginner Contest 050のA問題
https://atcoder.jp/contests/abc050/tasks/abc050_a
●問題文
joisinoお姉ちゃんは、A op B という式の値を計算したいと思っています。 ここで、A,B は整数で、op は、+ または - の記号です。 あなたの仕事は、joisinoお姉ちゃんの代わりにこれを求めるプログラムを作ることです。
●制約
- 1≦A,B≦10^9
- op は、+ または - の記号である。
●入力
入力は以下の形式で標準入力から与えられる。
A op B
●出力
式の値を出力せよ。
■回答
●愚直に書く
opが+
か-
かで条件分岐すれば良いか?
あ、opだけ整数じゃないからgets.split.map(&:to_i)
が使えないのか…!
a, op, b = gets.split
if op == "+"
puts a.to_i + b.to_i
else
puts a.to_i - b.to_i
end
通った!
もっと綺麗にできそう。
とりあえず変数を追加してto_i
の重複をなくすか。
a, op, b = gets.split
a_i = a.to_i
b_i = b.to_i
if op == "+"
puts a_i + b_i
else
puts a_i - b_i
end
全体のコード長は長くなったけど見やすくはなった、かな…?
●メソッド化して書く
メソッドを作る練習のために、あえてそういう書き方をする。
メソッドにしようとするとうまくいかない…。
下記はエラーになる。
def main
a = read_nums[0].to_i
op = read_nums[1]
b = read_nums[2].to_i
puts a
end
def calculation(a, b, op)
op == "+" ? a + b : a - b
end
def read_nums
gets.split
end
main
read_nums
を3回呼び出してるのがダメっぽいけど改善方法がパッと思い浮かばないな〜。
あ〜〜〜そうだ、メインメソッドで一回別の変数に入れればread_nums
の参照は一度で済むのか。これ何回かやったな…汗。
忘れていたことをもう一度できたので良しとしよう。
def main
nums = read_nums
a = nums.slice(0).to_i
op = nums.slice(1)
b = nums.slice(2).to_i
puts calculation(a, b, op)
end
def calculation(a, b, op)
op == "+" ? a + b : a - b
end
def read_nums
gets.split
end
main
通った!
変数の名前はちょっと改善の余地がありそうだが…。
●リファクタリング/別アプローチ
三項演算子。
a, op, b = gets.split
a_i = a.to_i
b_i = b.to_i
puts op == "+" ? a_i + b_i : a_i - b_i
通った!
●他の方の回答例
トップの回答が衝撃的な短さだった笑。
p eval *$<
下記くらいのほうが今の自分には良いかも↓
p eval gets.chomp
eval
はAtCoderでよく見かけつつスルーしてたのでここで一度ちゃんと調べてみる。
eval(expr) -> object
文字列 expr を Ruby プログラムとして評価してその結果を返します。]
(Kernel.#evalより)
つまり今回で言うと、gets.chomp
して取得した"5 + 2"
みたいな整数のカタマリをそのまま5 + 2
として計算してくれるってことか。めちゃくちゃ便利…!今回の問題はevalを使うというのが最低条件と言える。
●出てきたメソッド等
公式リファレンスを見る訓練。
■振り返りなど
- 今までスルーしていた
eval
について少しわかったので良かった。使いこなせるようになりたい。 - メソッド化の方も手こずってしまったけど、その分練習する意味がある回だった。