はじめに
paiza×Qiitaコラボキャンペーン のDランク問題のコードゴルフにRubyで挑戦しました。
自分なりの解説も交えています。
恐らく最短ではないと思います。ですがせっかくの機会なので、自分の知見をまとめる目的で執筆しました。
さらに短くなるなどございましたら、コメントよろしくお願いいたします!
N倍の文字列
問題概要
標準入力で与えられた整数個*
を繋げた文字列を出力してください。
Rubyコードゴルフ解答(16文字)
$><<?**gets.to_i
解説
上記の解答を分かりやすく書くと、以下のようになります。
puts "*"*gets.to_i
文字*
を標準入力で得た回数だけ連結した文字列を標準出力しています。
ここから2箇所短くする余地があります。
-
"*"
の部分です。文字列が1文字の場合に限り、Rubyの文字リテラルが利用できます。そのため"*"
は?*
と置き換えられます。 -
puts
の部分です。Rubyでは特殊変数$>
がputs
やp
のデフォルト出力先になっています。その特殊変数$>
に文字列を流し込むイメージで、$><<
と表現できます。
恩恵としてputs
直後に必要だった半角スペースが削除できます。以下のようになります。puts "Hello" $><<"Hello" #good
Eメールアドレス
問題概要
2行で与えられる文字列を、@
を間に挟んで連結してください。
Rubyコードゴルフ解答(17文字)
$><<`dd`.split*?@
解説
ポイントは3箇所です。
-
`dd`
の部分です。標準入力2行の受け取りを1度で済ませます。Rubyではバッククオートで外部コマンドを利用できます。`dd`
とすると、全行を一気に文字列として読み込むことができます。
確認のため入力例1で`dd`
で受け取ったものを確認すると、"paiza\nexample.com\n"
という、改行記号\n
も混在した1つの文字列となっています。 -
.split
の部分です。1.で受け取った文字列"paiza\nexample.com\n"
を加工します。
まずは、改行記号で文字列を分割します。String#splitが便利です。改行された結果が配列["paiza", "example.com"]
となります。 -
*?@
の部分です。配列["paiza", "example.com"]
の各要素をArray#*で結合することができます。以下が使用例です。結合する文字列には、先ほどの文字リテラルを用いて、"@"
ではなく?@
として1文字削除しています。p ["A","B","C"]*"X" #=> "AXBXC" p [1,2,3]*"X" #=> "1X2X3" 配列の要素が文字列以外の時、文字列への型変換が試されます
足し算
問題概要
空白区切りで与えられる2つの整数の和を出力してください。
Rubyコードゴルフ解答(16文字)
p eval`tr ' ' +`
解説
ポイントは3箇所です。
-
eval
の部分です。今回の全体方針としては、与えられた文字列を足し算の式の形の文字列に加工して、eval
で実行しています。Kernel.#evalが利用できます。これは与えられた文字列をRubyプログラムとして実行します。例えば以下のようになります。p eval("1+3") #=> 4 eval("3.times{puts 'Hello'}") #=> Helloが3行出力される
-
`tr ' ' +`
の部分です。先ほど述べたように、eval
で実行される文字列を作ります。目標は、例えば入力が"1 1"
のとき、"1+1"
という文字列にしたいです。
これは間に存在する半角スペースを"+"
という文字列に置換すればよいです。これは、先ほど紹介した外部コマンドを利用する方法で、tr
を用いればよいです。tr
コマンドで入力を受け取りながら、半角スペースを"+"
に置換しています。 -
実は
eval(`tr ' ' +` )
としなくてもeval`tr ' ' +`
で動きます。Rubyでは多くの箇所で引数の括弧を省略でき、eval
直後の半角スペースも今回は省略しても正しく認識してくれます。
一番小さい値
問題概要
5行の各整数のうち最小値を出力してください。
Rubyコードゴルフ解答(22文字)
puts`sort -n`.split[0]
解説
外部コマンド`sort -n`
を使用しています。全行を数値として解釈してソートしています。ソートした結果の文字列は、入力例1ですと"4\n8\n10\n12\n46\n"
となっています。
この文字列の最初の\n
の直前までが欲しいので、split
してできた配列["4", "8", "10", "12", "46"]
の最初の要素を[0]
で取り出します。
文字列の一致
問題概要
2行の各文字列が、一致しているか判定してください
Rubyコードゴルフ解答(28文字)
puts gets==gets+?\n?:OK: :NG
puts gets==gets ? :OK: :NG #本来ならこれで…
解説
1行ずつそれぞれgets
で受け取り、素直に比較する方針です。
もう1箇所ポイントは、3項演算子の時の文字列出力の書き方です。出力する文字列をシンボルとしても、puts
の際に文字列に変換されます。以下が短縮の流れです。
puts gets==gets ? "OK" : "NG"
puts gets==gets ? :OK : :NG #文字列をシンボルに変更
puts gets==gets ? :OK: :NG #OKの直後のスペースは削除可能
puts gets==gets?:OK: :NG #gets?というメソッドが無いためこれは不可。
本来ならこれで良いはずなのですが、ジャッジケースの不備?のため、末尾に改行が入っておらず、+?\n
で対処しています。またこれに伴い?
前後のスペースも削除できました。
おわりに
実は今回Qiita初投稿で、執筆しながら、記事にするというのはとても難しいと感じました。
いつもQiitaの投稿に大変お世話になっています。
投稿者の皆様、いつも素晴らしい記事をありがとうございます!