Paizaで遊ぶ(Ruby) #1 

こんにちは!おふとん王国の土曜日,とても平和です.

oftonkingdom.hatenablog.com パーフェクトRubyを読んでいますが,インプット中心で実際のコードを書いていなかったので練習のためRubyでPaizaのB問題あたりを大量に解いてみました.

実際に書いてみるといろいろ足りないところがわかったので復習のためのエントリを書いてみます.競技プログラミングのいろんな問題に共通する話だと思うから問題のネタバレにはならない…はず

(正確には足りないと言っても,競技プログラミングっぽいプログラムを書くときの知識として足りないものなので,アプリケーション開発(最終目標)に向けた勉強とはまた話が違ってくるのかもしれないが,共通部分もあると思うので書いてみます.)

それにしても言語の本を買って体系的に勉強していてよかったな,と思う場面は非常に多かったです.もともとパーフェクトRubyを読み始めたのも,「分厚い言語の入門書を一冊極めるといい」という話をどこかで聞いたことがあるからなのですが,なんとなくその効果を実感しています.

以下,復習記録です.

StringやEnumerable,Arrayのメソッドのうち,よく使うものは秒で出てくるようになりたい

こういうニーズを感じたときこそ記憶が定着しやすくなるはず!というわけでパーフェクトRuby「5-2 String」「5-5 Enumerable」をざっと読み直しました.以下メモ.

  • StringやArrayで長さを求めるメソッド,sizeかlengthどっちだっけ?となったけど,どっちも大丈夫だった
  • Enumerableの検索系メソッド Enumerable#grep,Enumerable#detect(Enumerable#find),Enumerable#select
  • Array#popは破壊的メソッドであり自身を変更する.戻り値は,取り除いた要素そのものである(ここではまった). また,要素を指定して削除する場合はArray#delete(完全に忘れていました).
  • Array#eachをArray#foreachと書いてしまう.他言語の癖が…
  • Array#[]で範囲オブジェクトを指定できるのとても便利(今日書いてみて実感した)

変数のスコープについて忘れている

メソッドの外で定義された変数はメソッドから使えない

scope.rb

cat = 'Russian Blue'

def display_cat
  cat.upcase
end

display_cat

出力

scope.rb:4:in `display_cat': undefined local variable or method `cat' for main:Object (NameError)

使わせたかったら$をつけてグローバル変数で宣言することになる

この一方でブロックの外で定義されたローカル変数はブロックの中でも使える.

標準入力でハマる

1行ずつ標準入力で受け付けた文字列をsplitで配列に分割したかった

str = gets

p str.split("")

「hello」と入力した場合の出力

["h", "e", "l", "l", "o", "\n"]

getsで取り込んだ文字列には改行コードが入ってしまうのでそれが配列の最後の要素に入ってしまう. とりあえず文字列の末尾の改行コードを1つ取り除くメソッドString#chompで対処したのちsplit("").(ぱっとString#chompが思いつかず少し迷走した.ついでにString#chopは改行コードにかかわらず文字列の末尾の1文字を取り除く) split("")と書いたけど,正規表現を使ってsplit(//)でも,String#each_charしてto_aを使ってもよかった.

ついでに標準入出力周りに限らず,競技プログラミングで使えそうなもの全般について見ておく.

Rubyで競技プログラミング - yhara.jp

qiita.com

gets.split.map(&:to_i)みたいなのはするっと書けるくらいになっていて成長したんじゃない?と.シンボルとかProcあたりがわかってきた!

$stdin.readで複数行一気に読み込み,配列に分割して多重代入とかも便利そう.

if文のthenを付け忘れがち

if 条件1 then
  処理1
elsif 条件2 then
  処理2
else
  上記以外の場合の処理
end

2次元配列の扱い

ふつうに迷った.以下の記事とか見た.

qiita.com

putsで配列を出力するとき,配列の要素が1行ずつ出力される

そう,2次元配列でもね.

array = [[1, 2], [3, 4], [5, 6]]

puts array

出力

1
2
3
4
5
6

Array#flattenが内部で呼び出されているということですかね.

1次元目だけ展開したかったんだ私は…というわけでArray#joinを使って文字列にした.

array.each do |line|
  puts line.join
end

出力

12
34
56

まとめ

ここのところ詰め込みすぎて頭がパンクしそうだったので,いい復習になりました.

この手の,ランクが付いたり時間制限があったりするものは楽しい.

AtCoderでも就職・転職につながるサービスがリリース予定らしいので,ぜひ挑戦していきたいところです.

prtimes.jp