3
1

はじめに

paiza×Qiitaコラボキャンペーン のDランク問題のコードゴルフにRubyで挑戦しました。
自分なりの解説も交えています。
恐らく最短ではないと思います。ですがせっかくの機会なので、自分の知見をまとめる目的で執筆しました。
さらに短くなるなどございましたら、コメントよろしくお願いいたします!

N倍の文字列

問題概要

標準入力で与えられた整数個*を繋げた文字列を出力してください。

Rubyコードゴルフ解答(16文字)

$><<?**gets.to_i

解説

上記の解答を分かりやすく書くと、以下のようになります。

puts "*"*gets.to_i

文字*を標準入力で得た回数だけ連結した文字列を標準出力しています。
ここから2箇所短くする余地があります。

  1. "*"の部分です。文字列が1文字の場合に限り、Rubyの文字リテラルが利用できます。そのため"*"?*と置き換えられます。
  2. putsの部分です。Rubyでは特殊変数$>putspのデフォルト出力先になっています。その特殊変数$>に文字列を流し込むイメージで、$><<と表現できます。
    恩恵としてputs直後に必要だった半角スペースが削除できます。以下のようになります。
    puts "Hello"
    $><<"Hello" #good
    

Eメールアドレス

問題概要

2行で与えられる文字列を、@を間に挟んで連結してください。

Rubyコードゴルフ解答(17文字)

$><<`dd`.split*?@

解説

ポイントは3箇所です。

  1. `dd`の部分です。標準入力2行の受け取りを1度で済ませます。Rubyではバッククオートで外部コマンドを利用できます`dd`とすると、全行を一気に文字列として読み込むことができます。
    確認のため入力例1で`dd`で受け取ったものを確認すると、"paiza\nexample.com\n"という、改行記号\nも混在した1つの文字列となっています。
  2. .splitの部分です。1.で受け取った文字列"paiza\nexample.com\n"を加工します。
    まずは、改行記号で文字列を分割します。String#splitが便利です。改行された結果が配列["paiza", "example.com"]となります。
  3. *?@の部分です。配列["paiza", "example.com"]の各要素をArray#*で結合することができます。以下が使用例です。結合する文字列には、先ほどの文字リテラルを用いて、"@"ではなく?@として1文字削除しています。
    p ["A","B","C"]*"X" #=> "AXBXC"
    p [1,2,3]*"X" #=> "1X2X3" 配列の要素が文字列以外の時、文字列への型変換が試されます
    

足し算

問題概要

空白区切りで与えられる2つの整数の和を出力してください。

Rubyコードゴルフ解答(16文字)

p eval`tr ' ' +`

解説

ポイントは3箇所です。

  1. evalの部分です。今回の全体方針としては、与えられた文字列を足し算の式の形の文字列に加工して、evalで実行しています。Kernel.#evalが利用できます。これは与えられた文字列をRubyプログラムとして実行します。例えば以下のようになります。

    p eval("1+3") #=> 4
    eval("3.times{puts 'Hello'}") #=> Helloが3行出力される
    
  2. `tr ' ' +`の部分です。先ほど述べたように、evalで実行される文字列を作ります。目標は、例えば入力が"1 1"のとき、"1+1"という文字列にしたいです。
    これは間に存在する半角スペースを"+"という文字列に置換すればよいです。これは、先ほど紹介した外部コマンドを利用する方法で、trを用いればよいです。trコマンドで入力を受け取りながら、半角スペースを"+"に置換しています。

  3. 実は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の投稿に大変お世話になっています。
投稿者の皆様、いつも素晴らしい記事をありがとうございます!

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1