「Rubyでどう書く?:連続した数列を範囲形式にまとめたい」をやってみる
Rubyでどう書く?:連続した数列を範囲形式にまとめたい
http://builder.japan.zdnet.com/sp/ruby-doukaku-panel/story/0,3800086254,20369264,00.htm・数値は、半角スペースで区切られた文字列で渡されます。
・続いている部分は、最初の数値と最後の数値を-(ハイフン)で繋いだ表記にします。
・連続が1回の場合(前の数も後ろの数も連続でない)は、-(ハイフン)では繋ぎません。
・出力は、「,」(カンマ)と半角スペースで区切られた文字列でなければなりません。例
"1 2 3" => "1-3."
"1 2 3 5 7 8" => "1-3, 5, 7-8."
"1 3 4 5 7" => "1, 3-5, 7."
という問題があったのでやってみる。
何も考えずJava脳で、調べ物もせずありあわせのRuby知識で書いたコードがこちら。
def renzoku(input) ins = input.split(" ") result = [] buff = [] ins.each do |i| i = i.to_i last = buff.last if last if i == (last + 1) buff << i else result << buff_to_s(buff) buff = [] buff << i end else buff << i end end result << buff_to_s(buff) result.join(",") end def buff_to_s(buff) if buff.size == 1 buff[0].to_s else buff.first.to_s + "-" + buff.last.to_s end end def eq(result, expected) puts "#{result} - #{expected}" if result == expected puts "ok" else puts "NG" end end eq(renzoku("1 2 3"), "1-3") eq(renzoku("1 2 3 5 7 8"), "1-3,5,7-8") eq(renzoku("1 3 4 5 7"), "1,3-5,7")
長いですね。assertっぽいメソッドも自分で作っちゃったけど、なんかあった気が。メインの部分だけで30行くらい?
とりあえずこれをリファクタリングしてみる。
require 'test/unit' include Test::Unit::Assertions def renzoku(input) buff, result = [],[] input = input.split(" ").map {|i|i.to_i} input.each do |i| if buff.last && (buff.last + 1) < i result << buff_to_s(buff) buff.clear end buff << i end result << buff_to_s(buff) result.join(",") end def buff_to_s(buff) if buff.size == 1 buff[0].to_s else buff.first.to_s + "-" + buff.last.to_s end end class TestRenzoku < Test::Unit::TestCase def test_renzoku assert_equal("1-3",renzoku("1 2 3")) assert_equal("1-3,5,7-8",renzoku("1 2 3 5 7 8")) assert_equal("1,3-5,7",renzoku("1 3 4 5 7")) end end
いまいちだな。。。
ちなみに元記事の回答例はこちら。
a = $*[0].split(' ').map{|i|i.to_i}+[nil] i = a[0] p a.inject([a[0].to_s]){|r, v| if i != v r << r.pop + "-#{i-1}" if 2 <= i - r.last.to_i break r unless v i = v r << i.to_s end i +=1 r }.join(', ')+'.'
回答例ではテストデータの投入部分がないですが、それでもかなり短くまとまっている。しかし、injectのあたりでムムッとなってしまうのは俺が知能指数が足りないからだろうか・・。かといって俺のコードのほうが分かりやすく美しい、というわけでもないけど・・。あ、最後にピリオドつけなきゃいけないのか。
def renzoku(line) b, r = [],[] line.split(' ').map{|j|j.to_i}.each do |i| if b.last && (b.last + 1) < i r << b2s(b) b.clear end b << i end r << b2s(b) r.join(',')+'.' end def b2s(b) r = b.first.to_s if b.size > 1 r += '-' + b.last.to_s end r end
じゃこんなかんじで。。。おやすみ。